From 56c2885565bacc4e67b9d1d57d02561f2609816b Mon Sep 17 00:00:00 2001 From: Alpha Chen Date: Fri, 19 Aug 2022 09:13:17 -0700 Subject: [PATCH] 14.3 --- rust/.gitignore | 1 + rust/Cargo.lock | 7 +++ rust/Cargo.toml | 8 ++++ rust/justfile | 2 + rust/src/chunk.rs | 112 ++++++++++++++++++++++++++++++++++++++++++++++ rust/src/main.rs | 5 +++ 6 files changed, 135 insertions(+) create mode 100644 rust/.gitignore create mode 100644 rust/Cargo.lock create mode 100644 rust/Cargo.toml create mode 100644 rust/justfile create mode 100644 rust/src/chunk.rs create mode 100644 rust/src/main.rs diff --git a/rust/.gitignore b/rust/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/rust/.gitignore @@ -0,0 +1 @@ +target diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 0000000..661ac0d --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "lox" +version = "0.1.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 0000000..f6e02e9 --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "lox" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/rust/justfile b/rust/justfile new file mode 100644 index 0000000..cdac729 --- /dev/null +++ b/rust/justfile @@ -0,0 +1,2 @@ +test-watch: + while true; do fd .*.rs | entr -d cargo test; done diff --git a/rust/src/chunk.rs b/rust/src/chunk.rs new file mode 100644 index 0000000..66ff7f8 --- /dev/null +++ b/rust/src/chunk.rs @@ -0,0 +1,112 @@ +use std::alloc::{self, Layout}; +use std::marker::PhantomData; +use std::ptr::{self, NonNull}; + +pub enum OpCode { + Return, +} + +pub struct Chunk { + count: usize, + capacity: usize, + code: NonNull, + _marker: PhantomData, +} + +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, + } + } + + // https://doc.rust-lang.org/nomicon/vec/vec-push-pop.html + pub fn write(&mut self, byte: u8) { + if self.count == self.capacity { + self.grow(); + } + + unsafe { + ptr::write(self.code.as_ptr().add(self.count), byte); + } + + // Can't fail, we'll OOM first. + self.count += 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::(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::(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 u8) { + 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 { + if self.count == 0 { + None + } else { + self.count -= 1; + unsafe { Some(ptr::read(self.code.as_ptr().add(self.count))) } + } + } +} + +// 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::(self.capacity).unwrap(); + unsafe { + alloc::dealloc(self.code.as_ptr() as *mut u8, layout); + } + } + } +} + +impl Default for Chunk { + fn default() -> Self { + Self::new() + } +} diff --git a/rust/src/main.rs b/rust/src/main.rs new file mode 100644 index 0000000..88c5d67 --- /dev/null +++ b/rust/src/main.rs @@ -0,0 +1,5 @@ +pub mod chunk; + +fn main() { + println!("Hello, world!"); +}