Skip to content

Commit

Permalink
Start working on a HashMap implementation using hashbrown::raw
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Aug 23, 2023
1 parent 7034356 commit 3cc1dee
Show file tree
Hide file tree
Showing 27 changed files with 652 additions and 305 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ default-members = [
[profile.bench]
lto = false
debug = true

[patch.crates-io]
hashbrown = { git = "https://github.com/udoprog/hashbrown", branch = "raw-infallible-context" }
8 changes: 8 additions & 0 deletions crates/rune-core/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,4 +478,12 @@ define! {
repr: Some("value?"),
doc: ["Allows the `?` operator to apply to values of this type."],
};

/// Protocol used when calculating a hash.
pub const [HASH, HASH_HASH]: Protocol = Protocol {
name: "hash",
hash: 0xf6cf2d9f416cef08u64,
repr: Some("let output = hash($value)"),
doc: ["Hash the given value."],
};
}
7 changes: 4 additions & 3 deletions crates/rune-macros/src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ where
value,
vm_result,
install_with,
non_null,
..
} = &tokens;

Expand Down Expand Up @@ -602,7 +603,7 @@ where
#vm_result::Err(err) => return #vm_result::Err(err),
};

#vm_result::Ok((&*value, guard))
#vm_result::Ok((#non_null::as_ref(&value), guard))
}
}

Expand All @@ -611,12 +612,12 @@ where
type Guard = #raw_into_mut;

unsafe fn unsafe_to_mut<'a>(value: #value) -> #vm_result<(&'a mut Self, Self::Guard)> {
let (value, guard) = match value.into_any_mut() {
let (mut value, guard) = match value.into_any_mut() {
#vm_result::Ok(value) => value,
#vm_result::Err(err) => return #vm_result::Err(err),
};

#vm_result::Ok((&mut *value, guard))
#vm_result::Ok((#non_null::as_mut(&mut value), guard))
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/rune-macros/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ impl Context {
iterator: path(&core, ["iter", "Iterator"]),
double_ended_iterator: path(&core, ["iter", "DoubleEndedIterator"]),
option: path(&core, ["option", "Option"]),
non_null: path(&core, ["ptr", "NonNull"]),
}
}
}
Expand Down Expand Up @@ -693,6 +694,7 @@ pub(crate) struct Tokens {
pub(crate) iterator: syn::Path,
pub(crate) double_ended_iterator: syn::Path,
pub(crate) option: syn::Path,
pub(crate) non_null: syn::Path,
}

impl Tokens {
Expand Down
73 changes: 33 additions & 40 deletions crates/rune-macros/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,21 @@ use syn::{Error, Token};
enum Path {
#[default]
None,
Instance(syn::Ident, syn::PathSegment),
Rename(syn::PathSegment),
Protocol(syn::Path),
}

#[derive(Default)]
pub(crate) struct FunctionAttrs {
instance: bool,
/// A free function.
free: bool,
/// Keep the existing function in place, and generate a separate hidden meta function.
keep: bool,
/// Path to register in.
path: Path,
/// Looks like an associated type.
self_type: bool,
self_type: Option<syn::PathSegment>,
}

impl FunctionAttrs {
Expand All @@ -35,6 +36,8 @@ impl FunctionAttrs {

if ident == "instance" {
out.instance = true;
} else if ident == "free" {
out.free = true;
} else if ident == "keep" {
out.keep = true;
} else if ident == "protocol" {
Expand All @@ -56,10 +59,6 @@ impl FunctionAttrs {
} else if ident == "path" {
input.parse::<Token![=]>()?;

if input.peek(Token![Self]) {
out.self_type = true;
}

let path = input.parse::<syn::Path>()?;

if path.segments.len() > 2 {
Expand All @@ -86,7 +85,10 @@ impl FunctionAttrs {
));
};

out.path = Path::Instance(first.ident, second);
out.self_type = Some(first);
out.path = Path::Rename(second);
} else if first.ident == "Self" {
out.self_type = Some(first);
} else {
out.path = Path::Rename(first);
}
Expand Down Expand Up @@ -200,37 +202,33 @@ impl Function {
(meta_fn, real_fn, sig, true)
};

let real_fn_path = if self.takes_self || attrs.self_type {
let mut path = syn::Path {
leading_colon: None,
segments: Punctuated::default(),
};

path.segments.push(syn::PathSegment::from(syn::Ident::new(
"Self",
self.sig.span(),
)));
path.segments.push(syn::PathSegment::from(real_fn));
let mut path = syn::Path {
leading_colon: None,
segments: Punctuated::default(),
};

syn::TypePath { qself: None, path }
} else {
let mut path = syn::Path {
leading_colon: None,
segments: Punctuated::default(),
};
match (self.takes_self, attrs.free, &attrs.self_type) {
(true, _, _) => {
path.segments
.push(syn::PathSegment::from(<Token![Self]>::default()));
path.segments.push(syn::PathSegment::from(real_fn));
}
(_, false, Some(self_type)) => {
path.segments.push(self_type.clone());
path.segments.push(syn::PathSegment::from(real_fn));
}
_ => {
path.segments.push(syn::PathSegment::from(real_fn));
}
}

path.segments.push(syn::PathSegment::from(real_fn));
syn::TypePath { qself: None, path }
};
let real_fn_path = syn::TypePath { qself: None, path };

let name_string = syn::LitStr::new(&self.sig.ident.to_string(), self.sig.ident.span());

let self_type;
let mut name;

if instance {
self_type = None;

name = 'out: {
syn::Expr::Lit(syn::ExprLit {
attrs: Vec::new(),
Expand All @@ -243,29 +241,24 @@ impl Function {
})
}
Path::None => name_string.clone(),
Path::Rename(last) | Path::Instance(_, last) => {
Path::Rename(last) => {
syn::LitStr::new(&last.ident.to_string(), last.ident.span())
}
}),
})
};
} else {
self_type = match &attrs.path {
Path::Instance(self_type, _) => Some(self_type.clone()),
_ => None,
};

name = match &attrs.path {
Path::None => expr_lit(&self.sig.ident),
Path::Rename(last) | Path::Instance(_, last) => expr_lit(&last.ident),
Path::Rename(last) => expr_lit(&last.ident),
Path::Protocol(protocol) => syn::Expr::Path(syn::ExprPath {
attrs: Vec::new(),
qself: None,
path: protocol.clone(),
}),
};

if !matches!(attrs.path, Path::Instance(..)) {
if attrs.self_type.is_none() {
let mut out = syn::ExprArray {
attrs: Vec::new(),
bracket_token: syn::token::Bracket::default(),
Expand All @@ -279,7 +272,7 @@ impl Function {

let arguments = match &attrs.path {
Path::None | Path::Protocol(_) => Punctuated::default(),
Path::Rename(last) | Path::Instance(_, last) => match &last.arguments {
Path::Rename(last) => match &last.arguments {
syn::PathArguments::AngleBracketed(arguments) => arguments.args.clone(),
syn::PathArguments::None => Punctuated::default(),
arguments => {
Expand Down Expand Up @@ -346,7 +339,7 @@ impl Function {

let build_with = if instance {
None
} else if let Some(self_type) = self_type {
} else if let Some(self_type) = &attrs.self_type {
Some(quote!(.build_associated::<#self_type>()))
} else {
Some(quote!(.build()))
Expand Down
2 changes: 1 addition & 1 deletion crates/rune/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ serde = { version = "1.0.163", default-features = false, features = ["derive", "
serde_bytes = { version = "0.11.9", default-features = false, features = ["alloc"] }
smallvec = { version = "1.10.0", default-features = false, features = ["serde", "const_new"] }
tracing = { version = "0.1.37", default-features = false, features = ["attributes"] }
hashbrown = { version = "0.13.2", features = ["serde"] }
hashbrown = { version = "0.14.0", features = ["raw", "serde"] }
musli = { version = "0.0.42", default-features = false, features = ["alloc"] }
slab = { version = "0.4.8", default-features = false }

Expand Down
6 changes: 3 additions & 3 deletions crates/rune/src/internal_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ macro_rules! from_value {
let value = vm_try!(value.$into());
let value = vm_try!(value.into_ref());
let (value, guard) = $crate::runtime::Ref::into_raw(value);
$crate::runtime::VmResult::Ok((&*value, guard))
$crate::runtime::VmResult::Ok((value.as_ref(), guard))
}
}

Expand All @@ -131,8 +131,8 @@ macro_rules! from_value {
) -> $crate::runtime::VmResult<(&'a mut Self, Self::Guard)> {
let value = vm_try!(value.$into());
let value = vm_try!(value.into_mut());
let (value, guard) = $crate::runtime::Mut::into_raw(value);
$crate::runtime::VmResult::Ok((&mut *value, guard))
let (mut value, guard) = $crate::runtime::Mut::into_raw(value);
$crate::runtime::VmResult::Ok((value.as_mut(), guard))
}
}

Expand Down
31 changes: 27 additions & 4 deletions crates/rune/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,15 @@ pub(crate) use rune_macros::__internal_impl_any;
/// generated Rune documentation.
/// * The name of arguments is captured to improve documentation generation.
/// * If an instance function is annotated this is detected (if the function
/// receives `self`). This behavior can be forced using `#[rune::function(instance)]` if
/// the function doesn't take `self`.
/// * 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)]`.
/// receives `self`). This behavior can be forced using
/// `#[rune::function(instance)]` if the function doesn't take `self`.
/// * The name of the function can be set using the `#[rune::function(path =
/// name)]` argument.
/// * An associated function can be specified with the `#[rune::function(path =
/// Type::name)]` argument. If `instance` is specified it is an associated
/// instance function that can be defined externally.
/// * Instance functions can be made a protocol function
/// `#[rune::function(protocol = STRING_DISPLAY)]`.
///
/// # Instance and associated functions
///
Expand Down Expand Up @@ -382,6 +387,24 @@ pub(crate) use rune_macros::__internal_impl_any;
/// The first part `Struct` in `Struct::new` is used to determine the type
/// the function is associated with.
///
/// Protocol functions can either be defined in an impl block or externally. To
/// define a protocol externally, you can simply do this:
///
/// ```rust
/// # use rune::Any;
/// # use rune::runtime::Formatter;
/// #[derive(Any)]
/// struct Struct {
/// /* .. */
/// }
///
/// #[rune::function(instance, protocol = STRING_DISPLAY)]
/// fn string_display(this: &Struct, f: &mut Formatter) -> std::fmt::Result {
/// /* .. */
/// # todo!()
/// }
/// ```
///
/// # Examples
///
/// Defining and using a simple free function:
Expand Down
18 changes: 18 additions & 0 deletions crates/rune/src/module/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,24 @@ impl Module {
/// The first part `Struct` in `Struct::new` is used to determine the type
/// the function is associated with.
///
/// Protocol functions can either be defined in an impl block or externally.
/// To define a protocol externally, you can simply do this:
///
/// ```rust
/// # use rune::Any;
/// # use rune::runtime::Formatter;
/// #[derive(Any)]
/// struct Struct {
/// /* .. */
/// }
///
/// #[rune::function(instance, protocol = STRING_DISPLAY)]
/// fn string_display(this: &Struct, f: &mut Formatter) -> std::fmt::Result {
/// /* .. */
/// # todo!()
/// }
/// ```
///
/// # Examples
///
/// ```
Expand Down
2 changes: 1 addition & 1 deletion crates/rune/src/modules/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub fn module() -> Result<Module, ContextError> {
/// let ty2 = Type::of_val(value2);
/// assert_eq!(ty1, ty2);
/// ```
#[rune::function(path = Type::of_val)]
#[rune::function(free, path = Type::of_val)]
#[inline]
fn type_of_val(value: Value) -> VmResult<Type> {
VmResult::Ok(Type::new(vm_try!(value.type_hash())))
Expand Down
6 changes: 3 additions & 3 deletions crates/rune/src/modules/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub fn module() -> Result<Module, ContextError> {
/// let bytes = Bytes::new();
/// assert_eq!(bytes, b"");
/// ```
#[rune::function(path = Bytes::new)]
#[rune::function(free, path = Bytes::new)]
#[inline]
pub const fn new() -> Bytes {
Bytes::new()
Expand All @@ -55,7 +55,7 @@ pub const fn new() -> Bytes {
/// bytes.extend(b"abcd");
/// assert_eq!(bytes, b"abcd");
/// ```
#[rune::function(path = Bytes::with_capacity)]
#[rune::function(free, path = Bytes::with_capacity)]
#[inline]
pub fn with_capacity(capacity: usize) -> Bytes {
Bytes::with_capacity(capacity)
Expand All @@ -69,7 +69,7 @@ pub fn with_capacity(capacity: usize) -> Bytes {
/// let bytes = Bytes::from_vec([b'a', b'b', b'c', b'd']);
/// assert_eq!(bytes, b"abcd");
/// ```
#[rune::function(path = Bytes::from_vec)]
#[rune::function(free, path = Bytes::from_vec)]
#[inline]
pub fn from_vec(bytes: Vec<u8>) -> Bytes {
Bytes::from_vec(bytes)
Expand Down
Loading

0 comments on commit 3cc1dee

Please sign in to comment.