use crate::seqstring::SeqString;
use may::sync::mpmc;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
#[derive(Debug)]
pub struct ChannelData {
pub sender: mpmc::Sender<Value>,
pub receiver: mpmc::Receiver<Value>,
}
impl Clone for ChannelData {
fn clone(&self) -> Self {
Self {
sender: self.sender.clone(),
receiver: self.receiver.clone(),
}
}
}
impl PartialEq for ChannelData {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self, other)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum WeaveMessage {
Value(Value),
Done,
Cancel,
}
#[derive(Debug)]
pub struct WeaveChannelData {
pub sender: mpmc::Sender<WeaveMessage>,
pub receiver: mpmc::Receiver<WeaveMessage>,
}
impl Clone for WeaveChannelData {
fn clone(&self) -> Self {
Self {
sender: self.sender.clone(),
receiver: self.receiver.clone(),
}
}
}
impl PartialEq for WeaveChannelData {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self, other)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MapKey {
Int(i64),
String(SeqString),
Bool(bool),
}
impl Hash for MapKey {
fn hash<H: Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
MapKey::Int(n) => n.hash(state),
MapKey::String(s) => s.as_str().hash(state),
MapKey::Bool(b) => b.hash(state),
}
}
}
impl MapKey {
pub fn from_value(value: &Value) -> Option<MapKey> {
match value {
Value::Int(n) => Some(MapKey::Int(*n)),
Value::String(s) => Some(MapKey::String(s.clone())),
Value::Bool(b) => Some(MapKey::Bool(*b)),
_ => None,
}
}
pub fn to_value(&self) -> Value {
match self {
MapKey::Int(n) => Value::Int(*n),
MapKey::String(s) => Value::String(s.clone()),
MapKey::Bool(b) => Value::Bool(*b),
}
}
}
#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Int(i64),
Float(f64),
Bool(bool),
String(SeqString),
Symbol(SeqString),
Variant(Arc<VariantData>),
Map(Box<HashMap<MapKey, Value>>),
Quotation {
wrapper: usize,
impl_: usize,
},
Closure {
fn_ptr: usize,
env: Arc<[Value]>,
},
Channel(Arc<ChannelData>),
WeaveCtx {
yield_chan: Arc<WeaveChannelData>,
resume_chan: Arc<WeaveChannelData>,
},
}
unsafe impl Send for Value {}
unsafe impl Sync for Value {}
#[derive(Debug, Clone, PartialEq)]
pub struct VariantData {
pub tag: SeqString,
pub fields: Vec<Value>,
}
impl VariantData {
pub fn new(tag: SeqString, fields: Vec<Value>) -> Self {
Self { tag, fields }
}
}
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Int(n) => write!(f, "{}", n),
Value::Float(n) => write!(f, "{}", n),
Value::Bool(b) => write!(f, "{}", b),
Value::String(s) => write!(f, "{:?}", s.as_str()),
Value::Symbol(s) => write!(f, ":{}", s.as_str()),
Value::Variant(v) => {
write!(f, ":{}", v.tag.as_str())?;
if !v.fields.is_empty() {
write!(f, "(")?;
}
for (i, field) in v.fields.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", field)?;
}
if !v.fields.is_empty() {
write!(f, ")")?;
}
Ok(())
}
Value::Map(m) => {
write!(f, "{{")?;
for (i, (k, v)) in m.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}: {}", k.to_value(), v)?;
}
write!(f, "}}")
}
Value::Quotation { .. } => write!(f, "<quotation>"),
Value::Closure { .. } => write!(f, "<closure>"),
Value::Channel(_) => write!(f, "<channel>"),
Value::WeaveCtx { .. } => write!(f, "<weave-ctx>"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem::{align_of, size_of};
#[test]
fn test_value_layout() {
println!("size_of::<Value>() = {}", size_of::<Value>());
println!("align_of::<Value>() = {}", align_of::<Value>());
assert_eq!(
size_of::<Value>(),
40,
"Value must be exactly 40 bytes, got {}",
size_of::<Value>()
);
use crate::tagged_stack::StackValue;
assert_eq!(
size_of::<StackValue>(),
8,
"StackValue must be 8 bytes, got {}",
size_of::<StackValue>()
);
assert_eq!(align_of::<Value>(), 8);
}
#[test]
fn test_value_int_layout() {
let val = Value::Int(42);
let ptr = &val as *const Value as *const u8;
unsafe {
let discriminant_byte = *ptr;
assert_eq!(
discriminant_byte, 0,
"Int discriminant should be 0, got {}",
discriminant_byte
);
let value_ptr = ptr.add(8) as *const i64;
let stored_value = *value_ptr;
assert_eq!(
stored_value, 42,
"Int value should be 42 at offset 8, got {}",
stored_value
);
}
}
#[test]
fn test_value_bool_layout() {
let val_true = Value::Bool(true);
let val_false = Value::Bool(false);
let ptr_true = &val_true as *const Value as *const u8;
let ptr_false = &val_false as *const Value as *const u8;
unsafe {
let discriminant = *ptr_true;
assert_eq!(
discriminant, 2,
"Bool discriminant should be 2, got {}",
discriminant
);
let value_ptr_true = ptr_true.add(8);
let value_ptr_false = ptr_false.add(8);
assert_eq!(*value_ptr_true, 1, "true should be 1");
assert_eq!(*value_ptr_false, 0, "false should be 0");
}
}
#[test]
fn test_value_display() {
assert_eq!(format!("{}", Value::Int(42)), "42");
assert_eq!(format!("{}", Value::Float(2.5)), "2.5");
assert_eq!(format!("{}", Value::Bool(true)), "true");
assert_eq!(format!("{}", Value::Bool(false)), "false");
let s = Value::String(SeqString::from("hello"));
assert_eq!(format!("{}", s), "\"hello\"");
let sym = Value::Symbol(SeqString::from("my-symbol"));
assert_eq!(format!("{}", sym), ":my-symbol");
}
}