This commit is contained in:
Ryan Chandler 2022-09-01 15:52:19 +01:00
parent aa2a6c8507
commit 7134db9472
No known key found for this signature in database
GPG Key ID: F113BCADDB3B0CCA
16 changed files with 0 additions and 504 deletions

View File

@ -1,8 +0,0 @@
[package]
name = "trunk_gc"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -1,31 +0,0 @@
# Notes
```rust
pub enum PhpValue {
Int(i64),
Array(Vec<GBox<PhpValue>>)
}
impl Trace<Self> for PhpValue {
fn trace(&self, tracer: Tracer) {
match self {
Self::Array(items) => {
for item in items {
item.trace(tracer);
}
},
_ => {},
}
}
}
let mut gc: Gc<PhpValue> = Gc::new();
let one = gc.hold(PhpValue::Int(1));
gc.root(PhpValue::Array(vec![
one,
]));
gc.collect();
```

View File

@ -1,91 +0,0 @@
use std::{collections::{HashSet, HashMap}, hash::Hash};
use std::rc::Rc;
pub struct Gc<T> {
sweep: usize,
heap: HashSet<GBox<T>>,
roots: HashMap<GBox<T>, Rc<()>>,
}
impl<T> Gc<T> {
pub fn new() -> Self {
Self {
sweep: 0,
heap: HashSet::default(),
roots: HashMap::default(),
}
}
pub fn hold(&mut self, value: T) -> GBox<T> {
let ptr = Box::into_raw(Box::new(value));
let gbox = GBox { ptr };
self.heap.insert(gbox);
gbox
}
pub fn get(&self, gbox: GBox<T>) -> Option<&T> {
if self.heap.contains(&gbox) {
Some(unsafe { &*gbox.ptr })
} else {
None
}
}
pub fn get_mut(&mut self, gbox: GBox<T>) -> Option<&mut T> {
if self.heap.contains(&gbox) {
Some(unsafe { &mut *gbox.ptr })
} else {
None
}
}
pub fn root(&mut self, value: T) -> GRoot<T> {
let gbox = self.hold(value);
let rc = Rc::new(());
self.roots.insert(gbox, rc);
GRoot { gbox }
}
pub fn collect(&mut self) {
let sweep = self.sweep + 1;
for gbox in &self.heap {
}
self.sweep = sweep;
}
}
pub struct GRoot<T> {
gbox: GBox<T>,
}
pub struct GBox<T> {
ptr: *mut T,
}
impl<T> PartialEq for GBox<T> {
fn eq(&self, other: &Self) -> bool {
self.ptr == other.ptr
}
}
impl<T> Eq for GBox<T> {}
impl<T> Clone for GBox<T> {
fn clone(&self) -> Self {
Self { ptr: self.ptr }
}
}
impl<T> Copy for GBox<T> {}
impl<T> Hash for GBox<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.ptr.hash(state);
}
}

View File

@ -1,45 +0,0 @@
#[allow(dead_code, unused_variables)]
mod gc;
#[cfg(test)]
mod tests {
use crate::gc::{Gc, GBox};
#[derive(Debug, PartialEq)]
pub struct Foo {
pub i: i64,
}
impl Drop for Foo {
fn drop(&mut self) {
println!("I'm being dropped!");
}
}
#[test]
fn it_returns_a_gbox() {
let mut gc: Gc<Foo> = Gc::new();
assert!(matches!(gc.hold(Foo { i: 100 }), GBox { .. }));
}
#[test]
fn it_can_retrieve_the_value_of_a_gbox() {
let mut gc: Gc<Foo> = Gc::new();
let my_gbox = gc.hold(Foo { i: 100 });
assert_eq!(gc.get(my_gbox), Some(&Foo { i: 100 }));
}
#[test]
fn it_can_return_a_mutable_ref_to_a_gbox_value() {
let mut gc: Gc<Foo> = Gc::new();
let my_gbox = gc.hold(Foo { i: 100 });
(*gc.get_mut(my_gbox).unwrap()).i = 200;
assert_eq!(gc.get(my_gbox), Some(&Foo { i: 200 }));
}
}

View File

@ -1,8 +0,0 @@
[package]
name = "trunk_interner"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -1,18 +0,0 @@
# Interner
This crate provides a simple string interner through the `Interner` structure. This structure allows you to retrieve a unique `Symbol` to a `&str`.
## Usage
```rust
use trunk_interner::{Interner, Symbol};
fn main() {
let mut interner = Interner::default();
let my_string_symbol: Symbol = interner.intern("Hello, world!");
let my_original_string: &str = interner.get(my_string_symbol);
}
```
If a `&str` is interned multiple times, the same `Symbol` will be returned, in theory minimizing the amount of memory used by your program due to a reduced number of `String` allocations.

View File

@ -1,62 +0,0 @@
use std::collections::HashMap;
/// A wrapper-type pointing to a unique string in the [`Interner`].
#[derive(Debug, Eq, PartialEq)]
#[repr(transparent)]
pub struct Symbol(u32);
/// The unoptimized singleton used for interning strings.
///
/// The structure uses a standard `HashMap` to map strings to indexes,
/// where those indexes point to a `String` inside of a `Vec<String>`.
///
/// The design of the interner isn't optimal right now since each
/// intern results into 2 allocations.
#[derive(Debug, Default)]
pub struct Interner {
map: HashMap<String, u32>,
storage: Vec<String>,
}
impl Interner {
/// Intern a `&str` and retrieve a unique [`Symbol`].
pub fn intern(&mut self, name: &str) -> Symbol {
if let Some(&index) = self.map.get(name) {
return Symbol(index);
}
let index = self.map.len() as u32;
self.map.insert(name.to_string(), index);
self.storage.push(name.to_string());
Symbol(index)
}
/// Retrieve tyhe `&str` for a given [`Symbol`].
pub fn get(&self, symbol: Symbol) -> &str {
self.storage[symbol.0 as usize].as_str()
}
}
#[cfg(test)]
mod tests {
use crate::{Interner, Symbol};
#[test]
fn it_can_intern_a_string() {
let mut interner = Interner::default();
assert_eq!(interner.intern("Hello, world!"), Symbol(0));
assert_eq!(interner.intern("Hello, world!"), Symbol(0));
}
#[test]
fn it_can_retrieve_an_interned_string() {
let mut interner = Interner::default();
let symbol = interner.intern("Hello, world!");
assert_eq!(interner.get(symbol), "Hello, world!");
}
}

View File

@ -1,9 +0,0 @@
[package]
name = "trunk_value"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
indexmap = "1.9.1"

View File

@ -1,43 +0,0 @@
use std::ops::Add;
use crate::{PhpValue, TypeError};
impl Add for PhpValue {
type Output = Result<Self, TypeError>;
fn add(self, rhs: Self) -> Self::Output {
Ok(match (&self, &rhs) {
(Self::Int(a), Self::Int(b)) => Self::Int(a + b),
(Self::Float(a), Self::Float(b)) => Self::Float(a + b),
(Self::Float(a), Self::Int(b)) | (Self::Int(b), Self::Float(a)) => {
Self::Float(a + *b as f64)
},
(Self::String(a), Self::Int(b)) | (Self::Int(b), Self::String(a)) => {
if a.parse::<i64>().is_ok() {
Self::Int(a.parse::<i64>().unwrap() + b)
} else {
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "+", rhs: rhs.inspect_type() })
}
},
(Self::String(a), Self::Float(b)) | (Self::Float(b), Self::String(a)) => {
if a.parse::<f64>().is_ok() {
Self::Float(a.parse::<f64>().unwrap() + b)
} else {
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "+", rhs: rhs.inspect_type() })
}
},
(Self::Array(a), Self::Array(b)) => {
let mut a_clone = a.clone();
for (key, value) in b {
if a_clone.contains_key(key) {
continue;
}
a_clone.insert(key.clone(), value.clone());
}
Self::Array(a_clone)
},
_ => return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "+", rhs: rhs.inspect_type() })
})
}
}

View File

@ -1,32 +0,0 @@
use std::ops::Div;
use crate::{PhpValue, TypeError};
impl Div for PhpValue {
type Output = Result<Self, TypeError>;
fn div(self, rhs: Self) -> Self::Output {
Ok(match (&self, &rhs) {
(Self::Int(a), Self::Int(b)) => Self::Int(a / b),
(Self::Float(a), Self::Float(b)) => Self::Float(a / b),
(Self::Float(a), Self::Int(b)) | (Self::Int(b), Self::Float(a)) => {
Self::Float(a / *b as f64)
},
(Self::String(a), Self::Int(b)) | (Self::Int(b), Self::String(a)) => {
if a.parse::<i64>().is_ok() {
Self::Int(a.parse::<i64>().unwrap() / b)
} else {
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "/", rhs: rhs.inspect_type() })
}
},
(Self::String(a), Self::Float(b)) | (Self::Float(b), Self::String(a)) => {
if a.parse::<f64>().is_ok() {
Self::Float(a.parse::<f64>().unwrap() / b)
} else {
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "/", rhs: rhs.inspect_type() })
}
},
_ => return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "/", rhs: rhs.inspect_type() })
})
}
}

View File

@ -1,25 +0,0 @@
mod value;
mod add;
mod sub;
mod mul;
mod div;
mod rem;
mod type_error;
pub use value::*;
pub use type_error::TypeError;
#[cfg(test)]
mod tests {
use crate::PhpValue;
#[test]
fn values_can_be_added() {
assert_eq!(PhpValue::Int(1) + PhpValue::Int(2), Ok(PhpValue::Int(3)));
assert_eq!(PhpValue::Float(1.5) + PhpValue::Float(2.5), Ok(PhpValue::Float(4.0)));
assert_eq!(PhpValue::Float(1.5) + PhpValue::Int(1), Ok(PhpValue::Float(2.5)));
assert_eq!(PhpValue::Int(1) + PhpValue::Float(1.5), Ok(PhpValue::Float(2.5)));
assert_eq!(PhpValue::String("1".into()) + PhpValue::Int(1), Ok(PhpValue::Int(2)));
assert_eq!(PhpValue::String("1".into()) + PhpValue::Float(1.0), Ok(PhpValue::Float(2.0)));
}
}

View File

@ -1,32 +0,0 @@
use std::ops::Mul;
use crate::{PhpValue, TypeError};
impl Mul for PhpValue {
type Output = Result<Self, TypeError>;
fn mul(self, rhs: Self) -> Self::Output {
Ok(match (&self, &rhs) {
(Self::Int(a), Self::Int(b)) => Self::Int(a * b),
(Self::Float(a), Self::Float(b)) => Self::Float(a * b),
(Self::Float(a), Self::Int(b)) | (Self::Int(b), Self::Float(a)) => {
Self::Float(a * *b as f64)
},
(Self::String(a), Self::Int(b)) | (Self::Int(b), Self::String(a)) => {
if a.parse::<i64>().is_ok() {
Self::Int(a.parse::<i64>().unwrap() * b)
} else {
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "*", rhs: rhs.inspect_type() })
}
},
(Self::String(a), Self::Float(b)) | (Self::Float(b), Self::String(a)) => {
if a.parse::<f64>().is_ok() {
Self::Float(a.parse::<f64>().unwrap() * b)
} else {
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "*", rhs: rhs.inspect_type() })
}
},
_ => return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "*", rhs: rhs.inspect_type() })
})
}
}

View File

@ -1,32 +0,0 @@
use std::ops::Rem;
use crate::{PhpValue, TypeError};
impl Rem for PhpValue {
type Output = Result<Self, TypeError>;
fn rem(self, rhs: Self) -> Self::Output {
Ok(match (&self, &rhs) {
(Self::Int(a), Self::Int(b)) => Self::Int(a % b),
(Self::Float(a), Self::Float(b)) => Self::Float(a % b),
(Self::Float(a), Self::Int(b)) | (Self::Int(b), Self::Float(a)) => {
Self::Float(a % *b as f64)
},
(Self::String(a), Self::Int(b)) | (Self::Int(b), Self::String(a)) => {
if a.parse::<i64>().is_ok() {
Self::Int(a.parse::<i64>().unwrap() % b)
} else {
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "%", rhs: rhs.inspect_type() })
}
},
(Self::String(a), Self::Float(b)) | (Self::Float(b), Self::String(a)) => {
if a.parse::<f64>().is_ok() {
Self::Float(a.parse::<f64>().unwrap() % b)
} else {
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "%", rhs: rhs.inspect_type() })
}
},
_ => return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "%", rhs: rhs.inspect_type() })
})
}
}

View File

@ -1,32 +0,0 @@
use std::ops::Sub;
use crate::{PhpValue, TypeError};
impl Sub for PhpValue {
type Output = Result<Self, TypeError>;
fn sub(self, rhs: Self) -> Self::Output {
Ok(match (&self, &rhs) {
(Self::Int(a), Self::Int(b)) => Self::Int(a - b),
(Self::Float(a), Self::Float(b)) => Self::Float(a - b),
(Self::Float(a), Self::Int(b)) | (Self::Int(b), Self::Float(a)) => {
Self::Float(a - *b as f64)
},
(Self::String(a), Self::Int(b)) | (Self::Int(b), Self::String(a)) => {
if a.parse::<i64>().is_ok() {
Self::Int(a.parse::<i64>().unwrap() - b)
} else {
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "-", rhs: rhs.inspect_type() })
}
},
(Self::String(a), Self::Float(b)) | (Self::Float(b), Self::String(a)) => {
if a.parse::<f64>().is_ok() {
Self::Float(a.parse::<f64>().unwrap() - b)
} else {
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "-", rhs: rhs.inspect_type() })
}
},
_ => return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "-", rhs: rhs.inspect_type() })
})
}
}

View File

@ -1,8 +0,0 @@
#[derive(Debug, Eq, PartialEq)]
pub enum TypeError {
UnsupportedOperandTypes {
lhs: String,
op: &'static str,
rhs: String,
}
}

View File

@ -1,28 +0,0 @@
use indexmap::IndexMap;
#[derive(Debug, Clone, PartialEq)]
pub enum PhpValue {
Int(i64),
Float(f64),
String(String),
Array(Array),
}
pub type Array = IndexMap<ArrayKey, PhpValue>;
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum ArrayKey {
Int(i64),
String(String),
}
impl PhpValue {
pub fn inspect_type(&self) -> String {
match self {
Self::Int(_) => "int".into(),
Self::Float(_) => "float".into(),
Self::String(_) => "string".into(),
_ => todo!(),
}
}
}