Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions src/builtin/functions/hash_table.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{Error, ErrorKind, TulispContext, TulispObject, destruct_eval_bind};
use std::{any::Any, cell::RefCell, collections::HashMap, rc::Rc};
use crate::{Error, ErrorKind, TulispAny, TulispContext, TulispObject, destruct_eval_bind};
use std::{cell::RefCell, collections::HashMap, rc::Rc};

struct TulispObjectEql(TulispObject);

Expand Down Expand Up @@ -28,6 +28,16 @@ impl From<TulispObject> for TulispObjectEql {
}
}

pub(crate) struct HashTable {
inner: RefCell<HashMap<TulispObjectEql, TulispObject>>,
}

impl std::fmt::Display for HashTable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "#<hash-table>")
}
}

pub(crate) fn add(ctx: &mut TulispContext) {
ctx.add_special_form("make-hash-table", |_ctx, args| {
if !args.null() {
Expand All @@ -37,18 +47,18 @@ pub(crate) fn add(ctx: &mut TulispContext) {
)
.with_trace(args.clone()));
}
let table: Rc<dyn Any> =
Rc::new(RefCell::new(HashMap::<TulispObjectEql, TulispObject>::new()));
let table: Rc<dyn TulispAny> = Rc::new(HashTable {
inner: RefCell::new(HashMap::new()),
});
Ok(table.into())
});

ctx.add_special_form("gethash", |ctx, args| {
destruct_eval_bind!(ctx, (key table) = args);
let binding = table.as_any()?;
let table = binding
.downcast_ref::<RefCell<HashMap<TulispObjectEql, TulispObject>>>()
.unwrap();
let table = binding.downcast_ref::<HashTable>().unwrap();
let value = table
.inner
.borrow_mut()
.get(&key.into())
.cloned()
Expand All @@ -61,10 +71,8 @@ pub(crate) fn add(ctx: &mut TulispContext) {
destruct_eval_bind!(ctx, (key value table) = args);

let binding = table.as_any()?;
let table = binding
.downcast_ref::<RefCell<HashMap<TulispObjectEql, TulispObject>>>()
.unwrap();
table.borrow_mut().insert(key.into(), value);
let table = binding.downcast_ref::<HashTable>().unwrap();
table.inner.borrow_mut().insert(key.into(), value);

Ok(TulispObject::nil())
});
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pub use error::{Error, ErrorKind};
pub mod lists;

mod value;
pub use value::TulispAny;
#[doc(hidden)]
pub use value::TulispValue;

Expand Down
14 changes: 10 additions & 4 deletions src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
ErrorKind, TulispValue,
cons::{self, Cons},
error::Error,
value::TulispAny,
};
use std::{
any::Any,
Expand Down Expand Up @@ -289,8 +290,7 @@ with `as_any`, and downcast to desired types.

## Example
```rust
# use tulisp::{TulispContext, destruct_bind, Error};
# use std::any::Any;
# use tulisp::{TulispContext, destruct_bind, Error, TulispAny};
# use std::rc::Rc;
#
# fn main() -> Result<(), Error> {
Expand All @@ -300,11 +300,17 @@ struct TestStruct {
value: i64,
}

impl std::fmt::Display for TestStruct {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "\"TestStruct {}\"", self.value)
}
}

ctx.add_special_form("make_any", |_ctx, args| {
destruct_bind!((inp) = args);
let inp: i64 = inp.try_into()?;

let any_obj: Rc<dyn Any> = Rc::new(TestStruct { value: inp });
let any_obj: Rc<dyn TulispAny> = Rc::new(TestStruct { value: inp });

Ok(any_obj.into())
});
Expand Down Expand Up @@ -569,7 +575,7 @@ tulisp_object_from!(f64);
tulisp_object_from!(&str);
tulisp_object_from!(String);
tulisp_object_from!(bool);
tulisp_object_from!(Rc<dyn Any>);
tulisp_object_from!(Rc<dyn TulispAny>);

impl FromIterator<TulispObject> for TulispObject {
fn from_iter<T: IntoIterator<Item = TulispObject>>(iter: T) -> Self {
Expand Down
18 changes: 13 additions & 5 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ use crate::{
error::{Error, ErrorKind},
object::Span,
};
use std::{any::Any, convert::TryInto, fmt::Write, rc::Rc};
use std::{
any::Any,
convert::TryInto,
fmt::{Display, Write},
rc::Rc,
};

#[doc(hidden)]
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -196,6 +201,9 @@ impl SymbolBindings {
}
}

pub trait TulispAny: Any + Display {}
impl<T: Any + Display> TulispAny for T {}

#[doc(hidden)]
#[derive(Clone)]
pub enum TulispValue {
Expand Down Expand Up @@ -237,7 +245,7 @@ pub enum TulispValue {
Splice {
value: TulispObject,
},
Any(Rc<dyn Any>),
Any(Rc<dyn TulispAny>),
Func(Rc<TulispFn>),
Macro(Rc<TulispFn>),
Defmacro {
Expand Down Expand Up @@ -281,7 +289,7 @@ impl std::fmt::Debug for TulispValue {
Self::Backquote { value } => f.debug_struct("Backquote").field("value", value).finish(),
Self::Unquote { value } => f.debug_struct("Unquote").field("value", value).finish(),
Self::Splice { value } => f.debug_struct("Splice").field("value", value).finish(),
Self::Any(arg0) => f.debug_tuple("Any").field(arg0).finish(),
Self::Any(arg0) => write!(f, "Any({:?} = {})", arg0.type_id(), arg0),
Self::Func(_) => write!(f, "Func"),
Self::Macro(_) => write!(f, "Macro"),
Self::Defmacro { params, body } => f
Expand Down Expand Up @@ -849,8 +857,8 @@ impl From<bool> for TulispValue {
}
}

impl From<Rc<dyn Any>> for TulispValue {
fn from(value: Rc<dyn Any>) -> Self {
impl From<Rc<dyn TulispAny>> for TulispValue {
fn from(value: Rc<dyn TulispAny>) -> Self {
TulispValue::Any(value)
}
}
Expand Down
12 changes: 9 additions & 3 deletions tests/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{any::Any, rc::Rc};
use tulisp::{Error, Iter, TulispContext, TulispObject, destruct_eval_bind};
use std::{fmt::Display, rc::Rc};
use tulisp::{Error, Iter, TulispAny, TulispContext, TulispObject, destruct_eval_bind};

macro_rules! tulisp_assert {
(@impl $ctx: expr, program:$input:expr, result:$result:expr $(,)?) => {
Expand Down Expand Up @@ -1155,11 +1155,17 @@ fn test_any() -> Result<(), Error> {
struct TestStruct {
value: i64,
}
impl Display for TestStruct {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "TestStruct({})", self.value)
}
}

let mut ctx = TulispContext::new();

ctx.add_special_form("make_any", |ctx, args| {
destruct_eval_bind!(ctx, (inp) = args);
let res: Rc<dyn Any> = Rc::new(TestStruct {
let res: Rc<dyn TulispAny> = Rc::new(TestStruct {
value: inp.try_into()?,
});

Expand Down