14.5.2
change qrvtrypwlqxspvtynmyzwxsuummtkpnr
commit 53584ab5a26ba04bf9cc222adfbf059b85fe142c
author Alpha Chen <alpha@kejadlen.dev>
date
parent ttppnowo
diff --git a/rust/src/chunk.rs b/rust/src/chunk.rs
index d94a15a..44d1e9f 100644
--- a/rust/src/chunk.rs
+++ b/rust/src/chunk.rs
@@ -1,52 +1,38 @@
-use std::alloc::{self, Layout};
-use std::marker::PhantomData;
-use std::ops::Deref;
-use std::ptr::{self, NonNull};
-
 #[repr(u8)]
 pub enum OpCode {
     Return,
 }
 
+type Value = f32;
+
 pub struct Chunk {
-    count: usize,
-    capacity: usize,
-    code: NonNull<OpCode>,
-    _marker: PhantomData<OpCode>,
+    code: Vec<OpCode>,
+    constants: Vec<Value>,
 }
 
-unsafe impl Send for Chunk {}
-unsafe impl Sync for Chunk {}
-
 impl Chunk {
     pub fn new() -> Self {
         Chunk {
-            count: 0,
-            capacity: 0,
-            code: NonNull::dangling(),
-            _marker: PhantomData,
+            code: Vec::new(),
+            constants: Vec::new(),
         }
     }
 
     // https://doc.rust-lang.org/nomicon/vec/vec-push-pop.html
     pub fn write(&mut self, op_code: OpCode) {
-        if self.count == self.capacity {
-            self.grow();
-        }
-
-        unsafe {
-            ptr::write(self.code.as_ptr().add(self.count), op_code);
-        }
+        self.code.push(op_code);
+    }
 
-        // Can't fail, we'll OOM first.
-        self.count += 1;
+    pub fn add_constant(&mut self, value: Value) -> usize{
+        self.constants.push(value);
+        self.constants.len() - 1
     }
 
     pub fn disassemble(&self, name: &str) {
         println!("== {} ==", name);
 
         let mut offset = 0;
-        while offset < self.count {
+        while offset < self.code.len() {
             offset = self.disassemble_instruction(offset);
         }
     }
@@ -54,7 +40,7 @@ impl Chunk {
     fn disassemble_instruction(&self, offset: usize) -> usize {
         print!("{:04} ", offset);
 
-        match self[offset] {
+        match self.code[offset] {
             OpCode::Return => self.simple_instruction("OP_RETURN", offset),
         }
     }
@@ -63,57 +49,6 @@ impl Chunk {
         println!("{}", name);
         offset + 1
     }
-
-    // https://doc.rust-lang.org/nomicon/vec/vec-alloc.html
-    fn grow(&mut self) {
-        // Crafting Interpreters: GROW_CAPACITY
-        let new_cap = if self.capacity < 8 {
-            8
-        } else {
-            // This can't overflow since self.capacity <= isize::MAX.
-            self.capacity * 2
-        };
-
-        // `Layout::array` checks that the number of bytes is <= usize::MAX,
-        // but this is redundant since old_layout.size() <= isize::MAX,
-        // so the `unwrap` should never fail.
-        let new_layout = Layout::array::<u8>(new_cap).unwrap();
-
-        // Ensure that the new allocation doesn't exceed `isize::MAX` bytes.
-        assert!(
-            new_layout.size() <= isize::MAX as usize,
-            "Allocation too large"
-        );
-
-        // Crafting Interpreters: GROW_ARRAY / reallocate
-        //   TODO: Handle shrinking maybe? We may need to
-        //         extract these out if it's used elsewhere
-        //         in the book
-        let new_ptr = if self.capacity == 0 {
-            unsafe { alloc::alloc(new_layout) }
-        } else {
-            let old_layout = Layout::array::<u8>(self.capacity).unwrap();
-            let old_ptr = self.code.as_ptr() as *mut u8;
-            unsafe { alloc::realloc(old_ptr, old_layout, new_layout.size()) }
-        };
-
-        // If allocation fails, `new_ptr` will be null, in which case we abort.
-        self.code = match NonNull::new(new_ptr as *mut OpCode) {
-            Some(p) => p,
-            None => alloc::handle_alloc_error(new_layout),
-        };
-        self.capacity = new_cap;
-    }
-
-    // https://doc.rust-lang.org/nomicon/vec/vec-push-pop.html
-    pub fn pop(&mut self) -> Option<OpCode> {
-        if self.count == 0 {
-            None
-        } else {
-            self.count -= 1;
-            unsafe { Some(ptr::read(self.code.as_ptr().add(self.count))) }
-        }
-    }
 }
 
 impl Default for Chunk {
@@ -121,23 +56,3 @@ impl Default for Chunk {
         Self::new()
     }
 }
-
-// https://doc.rust-lang.org/nomicon/vec/vec-dealloc.html
-impl Drop for Chunk {
-    fn drop(&mut self) {
-        if self.capacity != 0 {
-            while self.pop().is_some() {}
-            let layout = Layout::array::<u8>(self.capacity).unwrap();
-            unsafe {
-                alloc::dealloc(self.code.as_ptr() as *mut u8, layout);
-            }
-        }
-    }
-}
-
-impl Deref for Chunk {
-    type Target = [OpCode];
-    fn deref(&self) -> &[OpCode] {
-        unsafe { std::slice::from_raw_parts(self.code.as_ptr(), self.count) }
-    }
-}
diff --git a/rust/src/main.rs b/rust/src/main.rs
index 0e1a343..f1a76d2 100644
--- a/rust/src/main.rs
+++ b/rust/src/main.rs
@@ -1,6 +1,7 @@
 use chunk::{Chunk, OpCode};
 
 pub mod chunk;
+pub mod vec;
 
 fn main() {
     let mut chunk = Chunk::default();
diff --git a/rust/src/vec.rs b/rust/src/vec.rs
new file mode 100644
index 0000000..195e207
--- /dev/null
+++ b/rust/src/vec.rs
@@ -0,0 +1,118 @@
+// https://doc.rust-lang.org/nomicon/vec/vec.html
+
+use std::alloc::{self, Layout};
+use std::marker::PhantomData;
+use std::mem;
+use std::ops::{Deref, DerefMut};
+use std::ptr::{self, NonNull};
+
+pub struct Vec<T> {
+    ptr: NonNull<T>,
+    cap: usize,
+    len: usize,
+    _marker: PhantomData<T>,
+}
+
+unsafe impl<T: Send> Send for Vec<T> {}
+unsafe impl<T: Sync> Sync for Vec<T> {}
+
+impl<T> Vec<T> {
+    pub fn new() -> Self {
+        assert!(mem::size_of::<T>() != 0, "We're not ready to handle ZSTs");
+        Vec {
+            ptr: NonNull::dangling(),
+            len: 0,
+            cap: 0,
+            _marker: PhantomData,
+        }
+    }
+
+    pub fn push(&mut self, elem: T) {
+        if self.len == self.cap {
+            self.grow();
+        }
+
+        unsafe {
+            ptr::write(self.ptr.as_ptr().add(self.len), elem);
+        }
+
+        // Can't fail, we'll OOM first.
+        self.len += 1;
+    }
+
+    pub fn pop(&mut self) -> Option<T> {
+        if self.len == 0 {
+            None
+        } else {
+            self.len -= 1;
+            unsafe { Some(ptr::read(self.ptr.as_ptr().add(self.len))) }
+        }
+    }
+
+    fn grow(&mut self) {
+        let (new_cap, new_layout) = if self.cap == 0 {
+            (1, Layout::array::<T>(1).unwrap())
+        } else {
+            // This can't overflow since self.cap <= isize::MAX.
+            let new_cap = 2 * self.cap;
+
+            // `Layout::array` checks that the number of bytes is <= usize::MAX,
+            // but this is redundant since old_layout.size() <= isize::MAX,
+            // so the `unwrap` should never fail.
+            let new_layout = Layout::array::<T>(new_cap).unwrap();
+            (new_cap, new_layout)
+        };
+
+        // Ensure that the new allocation doesn't exceed `isize::MAX` bytes.
+        assert!(
+            new_layout.size() <= isize::MAX as usize,
+            "Allocation too large"
+        );
+
+        let new_ptr = if self.cap == 0 {
+            unsafe { alloc::alloc(new_layout) }
+        } else {
+            let old_layout = Layout::array::<T>(self.cap).unwrap();
+            let old_ptr = self.ptr.as_ptr() as *mut u8;
+            unsafe { alloc::realloc(old_ptr, old_layout, new_layout.size()) }
+        };
+
+        // If allocation fails, `new_ptr` will be null, in which case we abort.
+        self.ptr = match NonNull::new(new_ptr as *mut T) {
+            Some(p) => p,
+            None => alloc::handle_alloc_error(new_layout),
+        };
+        self.cap = new_cap;
+    }
+}
+
+impl<T> Drop for Vec<T> {
+    fn drop(&mut self) {
+        if self.cap != 0 {
+            while self.pop().is_some() {}
+            let layout = Layout::array::<T>(self.cap).unwrap();
+            unsafe {
+                alloc::dealloc(self.ptr.as_ptr() as *mut u8, layout);
+            }
+        }
+    }
+}
+
+impl<T> Deref for Vec<T> {
+    type Target = [T];
+    fn deref(&self) -> &[T] {
+        unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
+    }
+}
+
+impl<T> DerefMut for Vec<T> {
+    fn deref_mut(&mut self) -> &mut [T] {
+        unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
+    }
+}
+
+impl<T> Default for Vec<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}