Skip to content

Commit

Permalink
rune: Store Object in AnyObj instead of Mutable (relates #844)
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Nov 1, 2024
1 parent 87d9e1f commit 5dbb6d8
Show file tree
Hide file tree
Showing 26 changed files with 551 additions and 493 deletions.
10 changes: 7 additions & 3 deletions crates/rune-macros/src/from_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,13 @@ impl Expander<'_> {
#variant_data::Tuple(tuple) => match name {
#(#unnamed_matches,)* #missing,
},
#variant_data::Struct(object) => match name {
#(#named_matches,)* #missing,
},
#variant_data::Struct(data) => {
let object = variant.accessor(data);

match name {
#(#named_matches,)* #missing,
}
}
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions crates/rune-macros/src/to_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ impl Expander<'_> {
let ident = self.cx.field_ident(f)?;
_ = self.cx.field_attrs(&f.attrs);

let name = &syn::LitStr::new(&ident.to_string(), ident.span());
let name = syn::LitStr::new(&ident.to_string(), ident.span());

to_values.push(quote! {
object.insert(<#string as #try_from<_>>::try_from(#name)?, #to_value::to_value(self.#ident)?)
object.insert(<#string as #try_from<_>>::try_from(#name)?, #to_value::to_value(self.#ident)?)?
});
}

Expand Down
25 changes: 13 additions & 12 deletions crates/rune/src/compile/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -734,10 +734,10 @@ impl Context {
.copied()
.enumerate()
.map(|(position, name)| {
Ok((
Box::<str>::try_from(name)?,
meta::FieldMeta { position },
))
Ok(meta::FieldMeta {
name: name.try_into()?,
position,
})
})
.try_collect::<alloc::Result<_>>()??,
}),
Expand Down Expand Up @@ -765,6 +765,7 @@ impl Context {
enum_hash: ty.hash,
hash,
item: item.try_clone()?,
fields: fields.to_fields()?,
})),
type_parameters: Hash::EMPTY,
})?;
Expand Down Expand Up @@ -799,10 +800,10 @@ impl Context {
.copied()
.enumerate()
.map(|(position, name)| {
Ok((
Box::<str>::try_from(name)?,
meta::FieldMeta { position },
))
Ok(meta::FieldMeta {
name: name.try_into()?,
position,
})
})
.try_collect::<alloc::Result<_>>()??,
})
Expand Down Expand Up @@ -1116,10 +1117,10 @@ impl Context {
.copied()
.enumerate()
.map(|(position, name)| {
Ok((
Box::<str>::try_from(name)?,
meta::FieldMeta { position },
))
Ok(meta::FieldMeta {
name: name.try_into()?,
position,
})
})
.try_collect::<alloc::Result<_>>()??,
}),
Expand Down
104 changes: 22 additions & 82 deletions crates/rune/src/compile/ir/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ use crate::compile::meta;
use crate::compile::{self, IrErrorKind, ItemId, ModId, WithSpan};
use crate::hir;
use crate::query::{Query, Used};
use crate::runtime::{
self, BorrowRefRepr, ConstValue, Mutable, Object, OwnedTuple, RefRepr, Value,
};
use crate::runtime::{self, ConstValue, Object, OwnedTuple, RefRepr, Value};
use crate::TypeHash;

/// The interpreter that executed [Ir][crate::ir::Ir].
Expand Down Expand Up @@ -187,38 +185,18 @@ impl ir::Scopes {
ir::IrTargetKind::Name(name) => Ok(self.get_name(name, ir_target)?.clone()),
ir::IrTargetKind::Field(ir_target, field) => {
let value = self.get_target(ir_target)?;
let value = value.borrow_ref_repr().with_span(ir_target)?;
let object = value.borrow_ref::<Object>().with_span(ir_target)?;

let value = match value {
BorrowRefRepr::Mutable(value) => value,
actual => {
return Err(compile::Error::expected_type::<OwnedTuple>(
ir_target,
actual.type_info(),
));
}
let Some(value) = object.get(field.as_ref()) else {
return Err(compile::Error::new(
ir_target,
IrErrorKind::MissingField {
field: field.try_clone()?,
},
));
};

match &*value {
Mutable::Object(object) => {
if let Some(value) = object.get(field.as_ref()) {
return Ok(value.clone());
}
}
actual => {
return Err(compile::Error::expected_type::<OwnedTuple>(
ir_target,
actual.type_info(),
))
}
}

Err(compile::Error::new(
ir_target,
IrErrorKind::MissingField {
field: field.try_clone()?,
},
))
Ok(value.clone())
}
ir::IrTargetKind::Index(target, index) => {
let value = self.get_target(target)?;
Expand Down Expand Up @@ -284,30 +262,9 @@ impl ir::Scopes {
}
ir::IrTargetKind::Field(target, field) => {
let target = self.get_target(target)?;

let mut target = match target.as_ref_repr().with_span(ir_target)? {
RefRepr::Mutable(current) => current.borrow_mut().with_span(ir_target)?,
actual => {
return Err(compile::Error::expected_type::<Object>(
ir_target,
actual.type_info().with_span(ir_target)?,
));
}
};

match &mut *target {
Mutable::Object(object) => {
let field = field.as_ref().try_to_owned()?;
object.insert(field, value).with_span(ir_target)?;
}
actual => {
return Err(compile::Error::expected_type::<Object>(
ir_target,
actual.type_info(),
));
}
}

let mut object = target.borrow_mut::<Object>().with_span(ir_target)?;
let field = field.as_ref().try_to_owned()?;
object.insert(field, value).with_span(ir_target)?;
Ok(())
}
ir::IrTargetKind::Index(target, index) => {
Expand Down Expand Up @@ -374,35 +331,18 @@ impl ir::Scopes {
}
ir::IrTargetKind::Field(target, field) => {
let value = self.get_target(target)?;
let mut object = value.borrow_mut::<Object>().with_span(ir_target)?;

let mut value = match value.as_ref_repr().with_span(ir_target)? {
RefRepr::Mutable(value) => value.borrow_mut().with_span(ir_target)?,
actual => {
return Err(compile::Error::expected_type::<Object>(
ir_target,
actual.type_info().with_span(ir_target)?,
))
}
let Some(value) = object.get_mut(field.as_ref()) else {
return Err(compile::Error::new(
ir_target,
IrErrorKind::MissingField {
field: field.try_clone()?,
},
));
};

match &mut *value {
Mutable::Object(object) => {
let Some(value) = object.get_mut(field.as_ref()) else {
return Err(compile::Error::new(
ir_target,
IrErrorKind::MissingField {
field: field.try_clone()?,
},
));
};

op(value)
}
actual => Err(compile::Error::expected_type::<Object>(
ir_target,
actual.type_info(),
)),
}
op(value)
}
ir::IrTargetKind::Index(target, index) => {
let current = self.get_target(target)?;
Expand Down
17 changes: 16 additions & 1 deletion crates/rune/src/compile/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,28 @@ pub struct Alias {
#[non_exhaustive]
pub struct FieldsNamed {
/// Fields associated with the type.
pub(crate) fields: HashMap<Box<str>, FieldMeta>,
pub(crate) fields: Box<[FieldMeta]>,
}

impl FieldsNamed {
/// Coerce into a hashmap of fields.
pub(crate) fn to_fields(&self) -> alloc::Result<HashMap<Box<str>, usize>> {
let mut fields = HashMap::new();

for f in self.fields.iter() {
fields.try_insert(f.name.try_clone()?, f.position)?;
}

Ok(fields)
}
}

/// Metadata for a single named field.
#[derive(Debug, TryClone)]
pub struct FieldMeta {
/// Position of the field in its containing type declaration.
pub(crate) name: Box<str>,
/// The position of the field.
pub(crate) position: usize,
}

Expand Down
14 changes: 12 additions & 2 deletions crates/rune/src/compile/unit_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ impl UnitBuilder {
let rtti = Arc::new(Rtti {
hash,
item: pool.item(meta.item_meta.item).try_to_owned()?,
fields: HashMap::new(),
});

self.constants
Expand Down Expand Up @@ -348,6 +349,7 @@ impl UnitBuilder {
let rtti = Arc::new(Rtti {
hash: meta.hash,
item: pool.item(meta.item_meta.item).try_to_owned()?,
fields: HashMap::new(),
});

if self
Expand Down Expand Up @@ -404,6 +406,7 @@ impl UnitBuilder {
let rtti = Arc::new(Rtti {
hash: meta.hash,
item: pool.item(meta.item_meta.item).try_to_owned()?,
fields: HashMap::new(),
});

if self
Expand Down Expand Up @@ -443,12 +446,16 @@ impl UnitBuilder {
.functions
.try_insert(meta.hash, signature)?;
}
meta::Kind::Struct { .. } => {
meta::Kind::Struct {
fields: meta::Fields::Named(ref named),
..
} => {
let hash = pool.item_type_hash(meta.item_meta.item);

let rtti = Arc::new(Rtti {
hash,
item: pool.item(meta.item_meta.item).try_to_owned()?,
fields: named.to_fields()?,
});

self.constants
Expand All @@ -474,6 +481,7 @@ impl UnitBuilder {
enum_hash,
hash: meta.hash,
item: pool.item(meta.item_meta.item).try_to_owned()?,
fields: HashMap::new(),
});

if self
Expand Down Expand Up @@ -522,6 +530,7 @@ impl UnitBuilder {
enum_hash,
hash: meta.hash,
item: pool.item(meta.item_meta.item).try_to_owned()?,
fields: HashMap::new(),
});

if self
Expand Down Expand Up @@ -566,7 +575,7 @@ impl UnitBuilder {
}
meta::Kind::Variant {
enum_hash,
fields: meta::Fields::Named(..),
fields: meta::Fields::Named(ref named),
..
} => {
let hash = pool.item_type_hash(meta.item_meta.item);
Expand All @@ -575,6 +584,7 @@ impl UnitBuilder {
enum_hash,
hash,
item: pool.item(meta.item_meta.item).try_to_owned()?,
fields: named.to_fields()?,
});

if self
Expand Down
20 changes: 12 additions & 8 deletions crates/rune/src/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,15 @@ fn expr_object<'hir>(
}
});

let mut check_object_fields = |fields: &HashMap<_, meta::FieldMeta>, item: &Item| {
let mut fields = fields.try_clone()?;
let mut check_object_fields = |fields: &[meta::FieldMeta], item: &Item| {
let mut named = HashMap::new();

for f in fields.iter() {
named.try_insert(f.name.as_ref(), f)?;
}

for assign in assignments.iter_mut() {
match fields.remove(assign.key.1) {
match named.remove(assign.key.1) {
Some(field_meta) => {
assign.position = Some(field_meta.position);
}
Expand All @@ -310,11 +314,11 @@ fn expr_object<'hir>(
};
}

if let Some(field) = fields.into_keys().next() {
if let Some(field) = named.into_keys().next() {
return Err(compile::Error::new(
span,
ErrorKind::LitObjectMissingField {
field,
field: field.try_into()?,
item: item.try_to_owned()?,
},
));
Expand All @@ -335,7 +339,7 @@ fn expr_object<'hir>(
fields: meta::Fields::Empty,
..
} => {
check_object_fields(&HashMap::new(), item)?;
check_object_fields(&[], item)?;
hir::ExprObjectKind::EmptyStruct { hash: meta.hash }
}
meta::Kind::Struct {
Expand Down Expand Up @@ -1675,8 +1679,8 @@ fn struct_match_for(
meta::Fields::Empty if open => HashSet::new(),
meta::Fields::Named(st) => st
.fields
.keys()
.try_cloned()
.iter()
.map(|f| f.name.try_clone())
.try_collect::<alloc::Result<_>>()??,
_ => return Ok(None),
};
Expand Down
Loading

0 comments on commit 5dbb6d8

Please sign in to comment.