Skip to content

Commit

Permalink
Implement the CLONE protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Feb 16, 2024
1 parent 56260b0 commit 2f9bf3b
Show file tree
Hide file tree
Showing 27 changed files with 274 additions and 34 deletions.
5 changes: 1 addition & 4 deletions benches/benches/benchmarks/aoc_2020_19b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ fn aoc_2020_19b(b: &mut Criterion) {
fn clone(self) {
Self {
string: self.string,
position: self.position
position: clone(self.position)
}
}

Expand All @@ -178,7 +178,6 @@ fn aoc_2020_19b(b: &mut Criterion) {
fn completed(self) {
self.position == self.string.len()
}

}

enum Rule {
Expand All @@ -187,7 +186,6 @@ fn aoc_2020_19b(b: &mut Criterion) {
Seq(vs),
}


impl Rule {
fn validate(self, rules, str) {
let it = StrIter::new(str);
Expand Down Expand Up @@ -217,7 +215,6 @@ fn aoc_2020_19b(b: &mut Criterion) {
messages.iter().filter(|v| root.validate(rules, v)).count()
}


pub fn main(n) {
let r = get_rules();
let t1 = validate_all(r, n);
Expand Down
14 changes: 13 additions & 1 deletion crates/rune-alloc-macros/src/try_clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use crate::context::{Context, Tokens};

pub(super) fn expand(mut input: syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
let cx = Context::new();
let tokens = cx.tokens_with_module(None);

let attr = parse_type_attr(&cx, &input.attrs);

let tokens = cx.tokens_with_module(attr.module.as_ref());

if !attr.predicates.is_empty() {
input
.generics
Expand Down Expand Up @@ -161,6 +162,7 @@ pub(super) fn expand(mut input: syn::DeriveInput) -> Result<TokenStream, Vec<syn
struct TypeAttr {
predicates: syn::punctuated::Punctuated<syn::WherePredicate, syn::Token![,]>,
copy: bool,
module: Option<syn::Path>,
}

fn parse_type_attr(cx: &Context, input: &[syn::Attribute]) -> TypeAttr {
Expand All @@ -186,6 +188,16 @@ fn parse_type_attr(cx: &Context, input: &[syn::Attribute]) -> TypeAttr {
return Ok(());
}

if parser.path.is_ident("crate") {
if parser.input.parse::<Option<syn::Token![=]>>()?.is_some() {
attr.module = Some(parser.input.parse::<syn::Path>()?);
} else {
attr.module = Some(syn::parse_quote!(crate));
}

return Ok(());
}

Err(syn::Error::new(
parser.input.span(),
"unsupported attribute",
Expand Down
24 changes: 24 additions & 0 deletions crates/rune-core/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,4 +494,28 @@ define! {
repr: Some("let output = hash($value)"),
doc: ["Hash the given value."],
};

/// Protocol used when cloning a value.
pub const [CLONE, CLONE_HASH]: Protocol = Protocol {
name: "clone",
hash: 0x2af2c875e36971eu64,
repr: Some("let output = clone($value)"),
doc: ["Clone the given value."],
};

/// Protocol used when cloning a value.
pub const [SIZE_HINT, SIZE_HINT_HASH]: Protocol = Protocol {
name: "size_hint",
hash: 0x3de0975a7000dau64,
repr: Some("let output = $value.size_hint()"),
doc: ["Get the size hint of the given iterator."],
};

/// Protocol used when cloning a value.
pub const [NEXT_BACK, NEXT_BACK_HASH]: Protocol = Protocol {
name: "next_back",
hash: 0x91149fef42c0a8aeu64,
repr: Some("let output = $value.next_back()"),
doc: ["Get the next value from the back of the iterator."],
};
}
11 changes: 7 additions & 4 deletions crates/rune-macros/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,10 +460,13 @@ impl Context {
// Parse `#[rune(name = "..")]`
meta.input.parse::<Token![=]>()?;
attr.name = Some(meta.input.parse()?);
} else if meta.path == MODULE {
// Parse `#[rune(module = <path>)]`
meta.input.parse::<Token![=]>()?;
attr.module = Some(parse_path_compat(meta.input)?);
} else if meta.path == MODULE || meta.path == CRATE {
// Parse `#[rune(crate [= <path>])]`
if meta.input.parse::<Option<Token![=]>>()?.is_some() {
attr.module = Some(parse_path_compat(meta.input)?);
} else {
attr.module = Some(syn::parse_quote!(crate));
}
} else if meta.path == INSTALL_WITH {
// Parse `#[rune(install_with = <path>)]`
meta.input.parse::<Token![=]>()?;
Expand Down
1 change: 1 addition & 0 deletions crates/rune-macros/src/internals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub const PARSE: Symbol = Symbol("parse");
pub const NAME: Symbol = Symbol("name");
pub const ITEM: Symbol = Symbol("item");
pub const MODULE: Symbol = Symbol("module");
pub const CRATE: Symbol = Symbol("crate");
pub const INSTALL_WITH: Symbol = Symbol("install_with");

pub const CONSTRUCTOR: Symbol = Symbol("constructor");
Expand Down
1 change: 1 addition & 0 deletions crates/rune/src/compile/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ impl Context {
// This must go first, because it includes types which are used in other modules.
this.install(crate::modules::core::module()?)?;

this.install(crate::modules::clone::module()?)?;
this.install(crate::modules::num::module()?)?;
this.install(crate::modules::any::module()?)?;
this.install(crate::modules::bytes::module()?)?;
Expand Down
1 change: 1 addition & 0 deletions crates/rune/src/compile/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ impl Prelude {
this.add_prelude("char", ["char"])?;
this.add_prelude("dbg", ["io", "dbg"])?;
this.add_prelude("drop", ["mem", "drop"])?;
this.add_prelude("clone", ["clone", "clone"])?;
this.add_prelude("Err", ["result", "Result", "Err"])?;
this.add_prelude("file", ["macros", "builtin", "file"])?;
this.add_prelude("format", ["fmt", "format"])?;
Expand Down
2 changes: 2 additions & 0 deletions crates/rune/src/doc/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ impl<'m> Builder<'m> {
}

mod embed {
#[cfg(debug_assertions)]
use rust_alloc::boxed::Box;
#[cfg(debug_assertions)]
use rust_alloc::string::String;

use rust_embed::RustEmbed;
Expand Down
1 change: 1 addition & 0 deletions crates/rune/src/modules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod bytes;
#[cfg(feature = "capture-io")]
pub mod capture_io;
pub mod char;
pub mod clone;
pub mod cmp;
pub mod collections;
pub mod core;
Expand Down
37 changes: 37 additions & 0 deletions crates/rune/src/modules/clone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! The `std::clone` module.
use crate as rune;
use crate::runtime::{Value, VmResult};
use crate::{ContextError, Module};

#[rune::module(::std::clone)]
/// The `std::clone` module.
///
/// This module defines methods and types used when cloning values.
///
/// By default all values in rune are structurally shared, so in order to get a
/// unique instance of it you must call [`clone`] over it.
pub fn module() -> Result<Module, ContextError> {
let mut module = Module::from_meta(self::module_meta)?;
module.function_meta(clone)?;
Ok(module)
}

/// Clone the specified `value`.
///
/// # Examples
///
/// ```rune
/// let a = 42;
/// let b = a;
/// let c = clone(a);
///
/// a += 1;
/// assert_eq!(a, 43);
/// assert_eq!(b, 43);
/// assert_eq!(c, 42);
/// ```
#[rune::function]
fn clone(value: Value) -> VmResult<Value> {
value.clone_()
}
19 changes: 19 additions & 0 deletions crates/rune/src/modules/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,25 @@ fn is_writable(value: Value) -> bool {
value.is_writable()
}

/// Clone the specified `value`.
///
/// # Examples
///
/// ```rune
/// let a = 42;
/// let b = a;
/// let c = clone(a);
///
/// a += 1;
/// assert_eq!(a, 43);
/// assert_eq!(b, 43);
/// assert_eq!(c, 42);
/// ```
#[rune::function]
fn clone(value: Value) -> Value {
value.clone()
}

/// Stringify the given argument, causing it to expand to its underlying token
/// stream.
///
Expand Down
6 changes: 4 additions & 2 deletions crates/rune/src/runtime/control_flow.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::ops;

use crate as rune;
use crate::alloc::clone::TryClone;
use crate::alloc::fmt::TryWrite;
use crate::runtime::{Formatter, FromValue, ProtocolCaller, ToValue, Value, VmResult};
use crate::Any;
Expand All @@ -20,7 +20,9 @@ use crate::Any;
/// assert_eq!(c.0, 42);
/// assert_eq!(c, ControlFlow::Continue(42));
/// ```
#[derive(Debug, Clone, Any)]
#[derive(Debug, Clone, TryClone, Any)]
#[rune(crate)]
#[try_clone(crate)]
#[rune(builtin, static_type = CONTROL_FLOW_TYPE)]
pub enum ControlFlow {
/// Move on to the next phase of the operation as normal.
Expand Down
12 changes: 8 additions & 4 deletions crates/rune/src/runtime/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use musli::{Decode, Encode};
use serde::{Deserialize, Serialize};

use crate as rune;
use crate::alloc::clone::TryClone;
use crate::alloc::fmt::TryWrite;
use crate::alloc::String;
use crate::runtime::{Formatter, ProtocolCaller, Value, ValueKind, VmErrorKind, VmResult};
Expand Down Expand Up @@ -39,7 +40,7 @@ impl fmt::Display for AlignmentFromStrError {
}

/// A format specification, wrapping an inner value.
#[derive(Any, Debug, Clone)]
#[derive(Any, Debug, Clone, TryClone)]
#[rune(builtin, static_type = FORMAT_TYPE)]
pub struct Format {
/// The value being formatted.
Expand All @@ -51,7 +52,8 @@ pub struct Format {
from_value2!(Format, into_format_ref, into_format_mut, into_format);

/// A format specification.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Decode, Encode)]
#[derive(Debug, Clone, Copy, TryClone, Serialize, Deserialize, Decode, Encode)]
#[try_clone(copy)]
#[non_exhaustive]
pub struct FormatSpec {
/// Formatting flags.
Expand Down Expand Up @@ -441,7 +443,8 @@ impl fmt::Display for Type {
}

/// The alignment requested.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)]
#[derive(Debug, Clone, Copy, TryClone, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)]
#[try_clone(copy)]
#[non_exhaustive]
pub enum Alignment {
/// Left alignment.
Expand Down Expand Up @@ -505,9 +508,10 @@ pub enum Flag {
}

/// Format specification flags.
#[derive(Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)]
#[derive(Clone, Copy, TryClone, Default, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)]
#[repr(transparent)]
#[musli(transparent)]
#[try_clone(copy)]
pub struct Flags(u32);

impl Flags {
Expand Down
14 changes: 7 additions & 7 deletions crates/rune/src/runtime/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use crate::Hash;
/// let build_some = build;
/// assert_eq!(build_some(42), Some(42));
/// ```
#[derive(Any)]
#[derive(Any, TryClone)]
#[repr(transparent)]
#[rune(builtin, static_type = FUNCTION_TYPE)]
pub struct Function(FunctionImpl<Value>);
Expand Down Expand Up @@ -839,7 +839,7 @@ where
}
}

#[derive(Clone)]
#[derive(Clone, TryClone)]
struct FnHandler {
/// The function handler.
handler: Arc<FunctionHandler>,
Expand All @@ -853,7 +853,7 @@ impl fmt::Debug for FnHandler {
}
}

#[derive(Clone)]
#[derive(Clone, TryClone)]
struct FnOffset {
context: Arc<RuntimeContext>,
/// The unit where the function resides.
Expand Down Expand Up @@ -949,27 +949,27 @@ where
}
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, TryClone)]
struct FnUnitStruct {
/// The type of the empty.
rtti: Arc<Rtti>,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, TryClone)]
struct FnTupleStruct {
/// The type of the tuple.
rtti: Arc<Rtti>,
/// The number of arguments the tuple takes.
args: usize,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, TryClone)]
struct FnUnitVariant {
/// Runtime information fo variant.
rtti: Arc<VariantRtti>,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, TryClone)]
struct FnTupleVariant {
/// Runtime information fo variant.
rtti: Arc<VariantRtti>,
Expand Down
2 changes: 1 addition & 1 deletion crates/rune/src/runtime/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use core::future;
use core::pin::Pin;
use core::task::{Context, Poll};

use crate as rune;
use crate::alloc::{self, Box};
use crate::runtime::{ToValue, Value, VmErrorKind, VmResult};
use crate::Any;
Expand All @@ -16,6 +15,7 @@ type DynFuture = dyn future::Future<Output = VmResult<Value>> + 'static;
/// A type-erased future that can only be unsafely polled in combination with
/// the virtual machine that created it.
#[derive(Any)]
#[rune(crate)]
#[rune(builtin, static_type = FUTURE_TYPE)]
#[rune(from_value = Value::into_future)]
pub struct Future {
Expand Down
15 changes: 14 additions & 1 deletion crates/rune/src/runtime/generator.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::fmt;
use core::iter;

use crate as rune;
use crate::alloc::clone::TryClone;
use crate::runtime::{GeneratorState, Iterator, Value, Vm, VmErrorKind, VmExecution, VmResult};
use crate::Any;

Expand All @@ -23,6 +23,7 @@ use crate::Any;
/// assert!(g is Generator)
/// ```
#[derive(Any)]
#[rune(crate)]
#[rune(builtin, static_type = GENERATOR_TYPE, from_value_params = [Vm])]
#[rune(from_value = Value::into_generator, from_value_ref = Value::into_generator_ref, from_value_mut = Value::into_generator_mut)]
pub struct Generator<T>
Expand Down Expand Up @@ -133,3 +134,15 @@ where
.finish()
}
}

impl<T> TryClone for Generator<T>
where
T: TryClone + AsRef<Vm> + AsMut<Vm>,
{
#[inline]
fn try_clone(&self) -> Result<Self, rune_alloc::Error> {
Ok(Self {
execution: self.execution.try_clone()?,
})
}
}
Loading

0 comments on commit 2f9bf3b

Please sign in to comment.