title: How should you do pointer arithmetic in Rust?
body: <p>I know the answer is "you shouldn't"... but for the sake of argument, how <em>should</em> you do it?</p>
  
  <p>For example, if you wanted to write an alternative to <code>Vec&lt;T&gt;</code> that worked differently.</p>
  
  <p>I see that you can make 'something that compiles and runs' by transmuting <code>* mut T</code> values into <code>u64</code> and adding to them, then transmuting them back into <code>* mut T</code> and reading the value at the pointer (see example below). It seems to work, but it leaves a few of open questions:</p>
  
  <ol>
  <li><p>Will a <code>* mut T</code> pointer always fit into <code>u64</code>?</p></li>
  <li><p>Does <code>write()</code>ing to an unsafe pointer trigger pointer aliasing issues when the data is an arbitrary (i.e. not a managed type) data block from <code>libc:calloc</code>?</p></li>
  <li><p>This only works because I'm using a primitive type (<code>f64</code>). If this was a real data object, I would have to <code>forget()</code> the object first; but can you simply <code>write()</code> a <code>* mut T</code> into a target and then happily <code>read()</code> it out again later if the type is complex and has child records?</p></li>
  <li><p>Is this really the right way of doing this? It seems extremely awkward. I was expecting to find some unsafe <code>ptrtoint()</code> / <code>inttoptr()</code> pair, but I can't find anything like that. </p></li>
  </ol>
  
  <h2>Example</h2>
  
  <pre><code>extern crate libc;
  
  use std::mem::size_of;
  use std::ptr::write;
  use std::ptr::read;
  use std::mem::transmute;
  
  use libc::calloc;
  use libc::free;
  use libc::c_void;
  
  struct Array {
      length: usize,
      data: *mut f64,
  }
  
  impl Array {
      fn new(length: usize) -&gt; Array {
          unsafe {
              Array {
                  length: length,
                  data: calloc(size_of::&lt;f64&gt;(), length) as *mut f64,
              }
          }
      }
  
      fn set(&amp;mut self, offset: usize, value: f64) {
          if offset &lt; self.length {
              unsafe {
                  let root: *mut f64 = transmute(transmute::&lt;*mut f64, u64&gt;(self.data) +
                                                 (size_of::&lt;f64&gt;() * offset) as u64);
                  println!("Write: [{:?}] -&gt; {}", root, value);
                  write(root, value);
              }
          } else {
              println!("Write: Nope: [{}] is out of bounds", offset);
          }
      }
  
      fn get(&amp;self, offset: usize) -&gt; f64 {
          if offset &lt; self.length {
              unsafe {
                  let root: *const f64 = transmute(transmute::&lt;*mut f64, u64&gt;(self.data) +
                                                   (size_of::&lt;f64&gt;() * offset) as u64);
                  let rtn = read::&lt;f64&gt;(root);
                  println!("Read: [{:?}] -&gt; {}", root, rtn);
                  return rtn;
              }
          }
          println!("Read: Nope: [{}] is out of bounds", offset);
          0.0
      }
  }
  
  impl Drop for Array {
      fn drop(&amp;mut self) {
          unsafe {
              free(self.data as *mut c_void);
          }
      }
  }
  
  fn main() {
      let mut tmp = Array::new(4);
      tmp.set(0, 100.5);
      tmp.set(1, 101.5);
      tmp.set(2, 102.5);
      tmp.set(3, 103.5);
      tmp.set(4, 104.5);
      tmp.get(0);
      tmp.get(1);
      tmp.get(2);
      tmp.get(3);
      tmp.get(4);
  }
  </code></pre>
  
  <h2>Output</h2>
  
  <pre class="lang-none prettyprint-override"><code>Write: [0x7f04bdc1e080] -&gt; 100.5
  Write: [0x7f04bdc1e088] -&gt; 101.5
  Write: [0x7f04bdc1e090] -&gt; 102.5
  Write: [0x7f04bdc1e098] -&gt; 103.5
  Write: Nope: [4] is out of bounds
  Read: [0x7f04bdc1e080] -&gt; 100.5
  Read: [0x7f04bdc1e088] -&gt; 101.5
  Read: [0x7f04bdc1e090] -&gt; 102.5
  Read: [0x7f04bdc1e098] -&gt; 103.5
  Read: Nope: [4] is out of bounds
  </code></pre>