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
110 changes: 108 additions & 2 deletions crates/rune/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,107 @@ pub(crate) use rune_macros::__internal_impl_any;
/// * The name of the function can be set using the `#[rune::function(path = ...)]`.
/// * Instance functions can be made a protocol function `#[rune::function(protocol = STRING_DISPLAY)]`.
///
/// # Instance and associated functions
///
/// Instance and associated functions are a bit tricky to declare using
/// `#[rune::function]`, and care must be taken that you understand what needs
/// to be done. So this section is dedicated to documenting the ins and outs of
/// the process.
///
/// Briefly we should mention that instance functions are functions which are
/// associated with a type at runtime. Calling a value like `value.hello()`
/// invokes the `hello` associated function through the instance of `value`. The
/// exact type of `value` will then be used to look up which function to call.
/// They must take some kind of `self` parameter. Meanwhile associated functions
/// are just functions which are associated with a static type. Like
/// `String::new()`. The type `String` must then be in scope, and the function
/// does not take a `self` parameter.
///
/// This is how you declare an instance function which takes `&self` or `&mut
/// self`:
///
/// ```rust
/// # use rune::Any;
/// #[derive(Any)]
/// struct Struct {
/// /* .. */
/// }
///
/// impl Struct {
/// /// Get the length of the `Struct`.
/// #[rune::function]
/// fn len(&self) -> usize {
/// /* .. */
/// # todo!()
/// }
/// }
/// ```
///
/// If a function does not take `&self` or `&mut self`, you must specify that
/// it's an instance function using `#[rune::function(instance)]`. The first
/// argument is then considered the instance the function gets associated with:
///
/// ```rust
/// # use rune::Any;
/// #[derive(Any)]
/// struct Struct {
/// /* .. */
/// }
///
/// /// Get the length of the `Struct`.
/// #[rune::function(instance)]
/// fn len(this: &Struct) -> usize {
/// /* .. */
/// # todo!()
/// }
/// ```
///
/// To declare an associated function which does not receive the type we
/// must specify the path to the function using `#[rune::function(path =
/// Self::<name>)]`:
///
/// ```rust
/// # use rune::Any;
/// #[derive(Any)]
/// struct Struct {
/// /* .. */
/// }
///
/// impl Struct {
/// /// Construct a new [`Struct`].
/// #[rune::function(path = Self::new)]
/// fn new() -> Struct {
/// Struct {
/// /* .. */
/// }
/// }
/// }
/// ```
///
/// Or externally like this:
///
/// ```rust
/// # use rune::Any;
/// #[derive(Any)]
/// struct Struct {
/// /* .. */
/// }
///
/// /// Construct a new [`Struct`].
/// #[rune::function(path = Struct::new)]
/// fn new() -> Struct {
/// Struct {
/// /* .. */
/// }
/// }
/// ```
///
/// The first part `Struct` in `Struct::new` is used to determine the type
/// the function is associated with.
///
/// # Examples
///
/// A simple free function:
/// Defining and using a simple free function:
///
/// ```
/// use rune::{Module, ContextError};
Expand Down Expand Up @@ -329,7 +427,7 @@ pub(crate) use rune_macros::__internal_impl_any;
/// }
/// ```
///
/// Regular instance functions and protocol functions:
/// Regular instance and protocol functions:
///
/// ```
/// use rune::{Any, Module, ContextError};
Expand Down Expand Up @@ -364,6 +462,14 @@ pub(crate) use rune_macros::__internal_impl_any;
/// }
/// }
///
/// /// Display the string using the [`STRING_DISPLAY`] protocol.
/// ///
/// /// # Examples
/// ///
/// /// ```rune
/// /// let string = String::new("hello");
/// /// assert_eq!(format!("{}", string), "hello");
/// /// ```
/// #[rune::function(protocol = STRING_DISPLAY)]
/// fn display(&self, buffer: &mut std::string::String) -> fmt::Result {
/// write!(buffer, "{}", self.inner)
Expand Down
127 changes: 106 additions & 21 deletions crates/rune/src/module/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,27 +171,28 @@ impl Module {
/// }
///
/// impl MyBytes {
/// #[rune::function]
/// fn len(&self) -> usize {
/// self.queue.len()
/// }
/// }
///
/// // Register `len` without registering a type.
/// let mut module = Module::default();
/// let mut m = Module::default();
/// // Note: cannot do this until we have registered a type.
/// module.associated_function("len", MyBytes::len)?;
/// m.function_meta(MyBytes::len)?;
///
/// let mut context = rune::Context::new();
/// assert!(context.install(module).is_err());
/// assert!(context.install(m).is_err());
///
/// // Register `len` properly.
/// let mut module = Module::default();
/// let mut m = Module::default();
///
/// module.ty::<MyBytes>()?;
/// module.associated_function("len", MyBytes::len)?;
/// m.ty::<MyBytes>()?;
/// m.function_meta(MyBytes::len)?;
///
/// let mut context = Context::new();
/// assert!(context.install(module).is_ok());
/// assert!(context.install(m).is_ok());
/// # Ok::<_, rune::Error>(())
/// ```
pub fn ty<T>(&mut self) -> Result<TypeMut<'_, T>, ContextError>
Expand Down Expand Up @@ -780,11 +781,11 @@ impl Module {
/// }
/// }
///
/// let mut module = Module::default();
/// let mut m = Module::default();
///
/// module.ty::<MyBytes>()?;
/// module.function_meta(MyBytes::len)?;
/// module.function_meta(MyBytes::download)?;
/// m.ty::<MyBytes>()?;
/// m.function_meta(MyBytes::len)?;
/// m.function_meta(MyBytes::download)?;
/// # Ok::<_, rune::Error>(())
/// ```
#[inline]
Expand Down Expand Up @@ -878,8 +879,92 @@ impl Module {
/// If possible, [`Module::function_meta`] should be used since it includes
/// more useful information about the function.
///
/// This returns a [`ItemMut`], which is a handle that can be used to associate more metadata
/// with the inserted item.
/// This returns a [`ItemMut`], which is a handle that can be used to
/// associate more metadata with the inserted item.
///
/// # Replacing this with `function_meta` and `#[rune::function]`
///
/// This is how you declare an instance function which takes `&self` or
/// `&mut self`:
///
/// ```rust
/// # use rune::Any;
/// #[derive(Any)]
/// struct Struct {
/// /* .. */
/// }
///
/// impl Struct {
/// /// Get the length of the `Struct`.
/// #[rune::function]
/// fn len(&self) -> usize {
/// /* .. */
/// # todo!()
/// }
/// }
/// ```
///
/// If a function does not take `&self` or `&mut self`, you must specify that
/// it's an instance function using `#[rune::function(instance)]`. The first
/// argument is then considered the instance the function gets associated with:
///
/// ```rust
/// # use rune::Any;
/// #[derive(Any)]
/// struct Struct {
/// /* .. */
/// }
///
/// /// Get the length of the `Struct`.
/// #[rune::function(instance)]
/// fn len(this: &Struct) -> usize {
/// /* .. */
/// # todo!()
/// }
/// ```
///
/// To declare an associated function which does not receive the type we
/// must specify the path to the function using `#[rune::function(path =
/// Self::<name>)]`:
///
/// ```rust
/// # use rune::Any;
/// #[derive(Any)]
/// struct Struct {
/// /* .. */
/// }
///
/// impl Struct {
/// /// Construct a new [`Struct`].
/// #[rune::function(path = Self::new)]
/// fn new() -> Struct {
/// Struct {
/// /* .. */
/// }
/// }
/// }
/// ```
///
/// Or externally like this:
///
/// ```rust
/// # use rune::Any;
/// #[derive(Any)]
/// struct Struct {
/// /* .. */
/// }
///
/// /// Construct a new [`Struct`].
/// #[rune::function(path = Struct::new)]
/// fn new() -> Struct {
/// Struct {
/// /* .. */
/// }
/// }
/// ```
///
/// The first part `Struct` in `Struct::new` is used to determine the type
/// the function is associated with.
///
/// # Examples
///
Expand All @@ -892,26 +977,26 @@ impl Module {
/// }
///
/// impl MyBytes {
/// /// Construct a new empty bytes container.
/// #[rune::function(path = Self::new)]
/// fn new() -> Self {
/// Self {
/// queue: Vec::new(),
/// }
/// }
///
/// /// Get the number of bytes.
/// #[rune::function]
/// fn len(&self) -> usize {
/// self.queue.len()
/// }
/// }
///
/// let mut module = Module::default();
///
/// module.ty::<MyBytes>()?;
///
/// module.function(["MyBytes", "new"], MyBytes::new)?
/// .docs(["Construct a new empty bytes container."]);
/// let mut m = Module::default();
///
/// module.associated_function("len", MyBytes::len)?
/// .docs(["Get the number of bytes."]);
/// m.ty::<MyBytes>()?;
/// m.function_meta(MyBytes::new)?;
/// m.function_meta(MyBytes::len)?;
/// # Ok::<_, rune::Error>(())
/// ```
///
Expand Down
30 changes: 26 additions & 4 deletions crates/rune/src/modules/collections/hash_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use crate::no_std::collections;
use crate::no_std::prelude::*;

use crate as rune;
use crate::runtime::{FromValue, Iterator, Key, Value, VmErrorKind, VmResult};
use crate::runtime::{
EnvProtocolCaller, FromValue, Iterator, Key, ProtocolCaller, Value, VmErrorKind, VmResult,
};
use crate::{Any, ContextError, Module};

pub(super) fn setup(module: &mut Module) -> Result<(), ContextError> {
Expand Down Expand Up @@ -454,6 +456,14 @@ impl HashMap {
/// ```
#[rune::function(protocol = STRING_DEBUG)]
fn string_debug(&self, s: &mut String) -> VmResult<fmt::Result> {
self.string_debug_with(s, &mut EnvProtocolCaller)
}

pub(crate) fn string_debug_with(
&self,
s: &mut String,
caller: &mut impl ProtocolCaller,
) -> VmResult<fmt::Result> {
if let Err(fmt::Error) = write!(s, "{{") {
return VmResult::Ok(Err(fmt::Error));
}
Expand All @@ -469,7 +479,7 @@ impl HashMap {
return VmResult::Ok(Err(fmt::Error));
}

if let Err(fmt::Error) = vm_try!(value.string_debug(s)) {
if let Err(fmt::Error) = vm_try!(value.string_debug_with(s, caller)) {
return VmResult::Ok(Err(fmt::Error));
}

Expand Down Expand Up @@ -515,6 +525,14 @@ impl HashMap {
/// ```
#[rune::function(protocol = PARTIAL_EQ)]
fn partial_eq(&self, other: &Self) -> VmResult<bool> {
self.partial_eq_with(other, &mut EnvProtocolCaller)
}

pub(crate) fn partial_eq_with(
&self,
other: &Self,
caller: &mut impl ProtocolCaller,
) -> VmResult<bool> {
if self.map.len() != other.map.len() {
return VmResult::Ok(false);
}
Expand All @@ -524,7 +542,7 @@ impl HashMap {
return VmResult::Ok(false);
};

if !vm_try!(Value::partial_eq(v, v2)) {
if !vm_try!(Value::partial_eq_with(v, v2, caller)) {
return VmResult::Ok(false);
}
}
Expand Down Expand Up @@ -556,6 +574,10 @@ impl HashMap {
/// ```
#[rune::function(protocol = EQ)]
fn eq(&self, other: &Self) -> VmResult<bool> {
self.eq_with(other, &mut EnvProtocolCaller)
}

fn eq_with(&self, other: &Self, caller: &mut EnvProtocolCaller) -> VmResult<bool> {
if self.map.len() != other.map.len() {
return VmResult::Ok(false);
}
Expand All @@ -565,7 +587,7 @@ impl HashMap {
return VmResult::Ok(false);
};

if !vm_try!(Value::eq(v, v2)) {
if !vm_try!(Value::eq_with(v, v2, caller)) {
return VmResult::Ok(false);
}
}
Expand Down
Loading