Skip to content

Commit

Permalink
Extend Any to deal with internal types
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Aug 24, 2023
1 parent 3cc1dee commit 1204dd4
Show file tree
Hide file tree
Showing 28 changed files with 280 additions and 235 deletions.
158 changes: 136 additions & 22 deletions crates/rune-macros/src/any.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::BTreeMap;

use proc_macro2::{Span, TokenStream};
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned, ToTokens};
use rune_core::Hash;
use syn::punctuated::Punctuated;
Expand Down Expand Up @@ -50,8 +50,9 @@ impl InternalCall {
Err(error) => return Err(vec![error]),
};

let attr = TypeAttr::default();
let name = syn::LitStr::new(&name.to_string(), name.span());
expand_any(None, &self.path, type_hash, &name, &[], &tokens, &generics)
expand_any(attr, &self.path, type_hash, &name, &[], &tokens, &generics)
}
}

Expand Down Expand Up @@ -110,7 +111,7 @@ impl Derive {
let name = syn::LitStr::new(&name.to_string(), name.span());

expand_any(
attr.builtin,
attr,
ident,
type_hash,
&name,
Expand Down Expand Up @@ -470,7 +471,7 @@ fn expand_enum_install_with(

/// Expand the necessary implementation details for `Any`.
pub(super) fn expand_any<T>(
builtin: Option<Span>,
attr: TypeAttr,
ident: T,
type_hash: Hash,
name: &syn::LitStr,
Expand Down Expand Up @@ -504,20 +505,31 @@ where
vm_result,
install_with,
non_null,
box_,
static_type_mod,
from_value,
raw_ref,
raw_mut,
mut_,
ref_,
..
} = &tokens;

let (impl_generics, type_generics, where_clause) = generics.split_for_impl();

let generic_names = generics.type_params().map(|v| &v.ident).collect::<Vec<_>>();
let generic_names = if attr.static_type.is_some() {
vec![]
} else {
generics.type_params().map(|v| &v.ident).collect::<Vec<_>>()
};

let impl_named = if !generic_names.is_empty() {
quote! {
#[automatically_derived]
impl #impl_generics #named for #ident #type_generics #where_clause {
const BASE_NAME: #raw_str = #raw_str::from_str(#name);

fn full_name() -> Box<str> {
fn full_name() -> #box_<str> {
[#name, "<", &#(#generic_names::full_name(),)* ">"].join("").into_boxed_str()
}
}
Expand All @@ -541,29 +553,14 @@ where
}
};

let any = if builtin.is_none() {
let type_hash = type_hash.into_inner();

let make_hash = if !generic_names.is_empty() {
quote!(#hash::new_with_type_parameters(#type_hash, #hash::parameters([#(<#generic_names as #type_of>::type_hash()),*])))
} else {
quote!(#hash::new(#type_hash))
};

let impl_type_of = if attr.builtin.is_none() {
let type_parameters = if !generic_names.is_empty() {
quote!(#hash::parameters([#(<#generic_names as #type_of>::type_hash()),*]))
} else {
quote!(#hash::EMPTY)
};

Some(quote! {
#[automatically_derived]
impl #impl_generics #any for #ident #type_generics #where_clause {
fn type_hash() -> #hash {
#make_hash
}
}

#[automatically_derived]
impl #impl_generics #type_of for #ident #type_generics #where_clause {
#[inline]
Expand Down Expand Up @@ -592,6 +589,50 @@ where
Some(<Self as #type_of>::type_of())
}
}
})
} else if let Some(ty) = attr.static_type {
Some(quote! {
#[automatically_derived]
impl #impl_generics #type_of for #ident #type_generics #where_clause {
#[inline]
fn type_hash() -> #hash {
#static_type_mod::#ty.hash
}

#[inline]
fn type_info() -> #type_info {
#type_info::StaticType(#static_type_mod::#ty)
}
}

#[automatically_derived]
impl #impl_generics #maybe_type_of for #ident #type_generics #where_clause {
#[inline]
fn maybe_type_of() -> Option<#full_type_of> {
Some(<Self as #type_of>::type_of())
}
}
})
} else {
None
};

let any = if attr.builtin.is_none() {
let type_hash = type_hash.into_inner();

let make_hash = if !generic_names.is_empty() {
quote!(#hash::new_with_type_parameters(#type_hash, #hash::parameters([#(<#generic_names as #type_of>::type_hash()),*])))
} else {
quote!(#hash::new(#type_hash))
};

Some(quote! {
#[automatically_derived]
impl #impl_generics #any for #ident #type_generics #where_clause {
fn type_hash() -> #hash {
#make_hash
}
}

#[automatically_derived]
impl #impl_generics #unsafe_to_ref for #ident #type_generics #where_clause {
Expand Down Expand Up @@ -645,9 +686,82 @@ where
None
};

let impl_from_value = 'out: {
if let Some(path) = attr.from_value {
let ty = match &attr.from_value_params {
Some(params) => quote!(#ident<#params>),
None if generics.params.is_empty() => quote!(#ident),
_ => break 'out None,
};

Some(quote! {
impl #from_value for #ty {
fn from_value(value: Value) -> #vm_result<Self> {
let value = vm_try!(#path(value));
let value = vm_try!(value.take());
#vm_result::Ok(value)
}
}

impl #unsafe_to_ref for #ty {
type Guard = #raw_ref;

unsafe fn unsafe_to_ref<'a>(
value: #value,
) -> #vm_result<(&'a Self, Self::Guard)> {
let value = vm_try!(#path(value));
let value = vm_try!(value.into_ref());
let (value, guard) = #ref_::into_raw(value);
#vm_result::Ok((value.as_ref(), guard))
}
}

impl #unsafe_to_mut for #ty {
type Guard = #raw_mut;

unsafe fn unsafe_to_mut<'a>(
value: #value,
) -> #vm_result<(&'a mut Self, Self::Guard)> {
let value = vm_try!(#path(value));
let value = vm_try!(#shared::into_mut(value));
let (mut value, guard) = #mut_::into_raw(value);
#vm_result::Ok((value.as_mut(), guard))
}
}

impl #from_value for #shared<#ty> {
#[inline]
fn from_value(value: #value) -> #vm_result<Self> {
#path(value)
}
}

impl #from_value for #ref_<#ty> {
fn from_value(value: Value) -> #vm_result<Self> {
let value = vm_try!(#path(value));
let value = vm_try!(#shared::into_ref(value));
#vm_result::Ok(value)
}
}

impl #from_value for #mut_<#ty> {
fn from_value(value: Value) -> VmResult<Self> {
let value = vm_try!(#path(value));
let value = vm_try!(#shared::into_mut(value));
#vm_result::Ok(value)
}
}
})
} else {
None
}
};

Ok(quote! {
#install_with
#impl_named
#impl_type_of
#impl_from_value
#any
})
}
39 changes: 39 additions & 0 deletions crates/rune-macros/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ pub(crate) struct TypeAttr {
/// Indicates that this is a builtin type, so don't generate an `Any`
/// implementation for it.
pub(crate) builtin: Option<Span>,
/// Indicate a static type to use.
pub(crate) static_type: Option<syn::Ident>,
/// Method to use to convert from value.
pub(crate) from_value: Option<syn::Path>,
/// Method to use to convert from value.
pub(crate) from_value_params: Option<syn::punctuated::Punctuated<syn::Type, Token![,]>>,
}

/// Parsed variant attributes.
Expand Down Expand Up @@ -455,6 +461,18 @@ impl Context {
attr.constructor = true;
} else if meta.path == BUILTIN {
attr.builtin = Some(meta.path.span());
} else if meta.path == STATIC_TYPE {
meta.input.parse::<Token![=]>()?;
attr.static_type = Some(meta.input.parse()?);
} else if meta.path == FROM_VALUE {
meta.input.parse::<Token![=]>()?;
attr.from_value = Some(meta.input.parse()?);
} else if meta.path == FROM_VALUE_PARAMS {
meta.input.parse::<Token![=]>()?;
let content;
syn::bracketed!(content in meta.input);
attr.from_value_params =
Some(syn::punctuated::Punctuated::parse_terminated(&content)?);
} else {
return Err(syn::Error::new_spanned(
&meta.path,
Expand Down Expand Up @@ -545,6 +563,15 @@ impl Context {
Span::call_site(),
)));

let mut alloc = syn::Path {
leading_colon: Some(<Token![::]>::default()),
segments: Punctuated::default(),
};
alloc.segments.push(syn::PathSegment::from(syn::Ident::new(
"alloc",
Span::call_site(),
)));

let mut default_module;

let m = match module {
Expand All @@ -570,6 +597,10 @@ impl Context {
compile_error: path(m, ["compile", "Error"]),
context_error: path(m, ["compile", "ContextError"]),
from_value: path(m, ["runtime", "FromValue"]),
raw_ref: path(m, ["runtime", "RawRef"]),
raw_mut: path(m, ["runtime", "RawMut"]),
ref_: path(m, ["runtime", "Ref"]),
mut_: path(m, ["runtime", "Mut"]),
full_type_of: path(m, ["runtime", "FullTypeOf"]),
hash: path(m, ["Hash"]),
id: path(m, ["parse", "Id"]),
Expand Down Expand Up @@ -613,6 +644,8 @@ impl Context {
double_ended_iterator: path(&core, ["iter", "DoubleEndedIterator"]),
option: path(&core, ["option", "Option"]),
non_null: path(&core, ["ptr", "NonNull"]),
box_: path(&alloc, ["boxed", "Box"]),
static_type_mod: path(m, ["runtime", "static_type"]),
}
}
}
Expand Down Expand Up @@ -695,6 +728,12 @@ pub(crate) struct Tokens {
pub(crate) double_ended_iterator: syn::Path,
pub(crate) option: syn::Path,
pub(crate) non_null: syn::Path,
pub(crate) box_: syn::Path,
pub(crate) static_type_mod: syn::Path,
pub(crate) raw_ref: syn::Path,
pub(crate) raw_mut: syn::Path,
pub(crate) ref_: syn::Path,
pub(crate) mut_: syn::Path,
}

impl Tokens {
Expand Down
3 changes: 3 additions & 0 deletions crates/rune-macros/src/internals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ pub const INSTALL_WITH: Symbol = Symbol("install_with");

pub const CONSTRUCTOR: Symbol = Symbol("constructor");
pub const BUILTIN: Symbol = Symbol("builtin");
pub const STATIC_TYPE: Symbol = Symbol("static_type");
pub const FROM_VALUE: Symbol = Symbol("from_value");
pub const FROM_VALUE_PARAMS: Symbol = Symbol("from_value_params");
pub const GET: Symbol = Symbol("get");
pub const SET: Symbol = Symbol("set");
pub const COPY: Symbol = Symbol("copy");
Expand Down
2 changes: 2 additions & 0 deletions crates/rune-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
//!
//! This is part of the [Rune Language](https://rune-rs.github.io).
#![allow(clippy::manual_map)]

use ::quote::format_ident;
use syn::{Generics, Path};

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 @@ -10,8 +10,8 @@ macro_rules! resolve_context {

/// Build an implementation of `TypeOf` basic of a static type.
macro_rules! impl_static_type {
(impl <$($p:ident),*> $ty:ty => $static_type:expr) => {
impl<$($p,)*> $crate::runtime::TypeOf for $ty {
(impl <$($p:ident),*> $ty:ty => $static_type:expr $(, where $($where:tt)+)?) => {
impl<$($p,)*> $crate::runtime::TypeOf for $ty $(where $($where)+)* {
#[inline]
fn type_hash() -> $crate::Hash {
$static_type.hash
Expand All @@ -23,7 +23,7 @@ macro_rules! impl_static_type {
}
}

impl<$($p,)*> $crate::runtime::MaybeTypeOf for $ty {
impl<$($p,)*> $crate::runtime::MaybeTypeOf for $ty $(where $($where)+)* {
#[inline]
fn maybe_type_of() -> Option<$crate::runtime::FullTypeOf> {
Some(<$ty as $crate::runtime::TypeOf>::type_of())
Expand Down
2 changes: 1 addition & 1 deletion crates/rune/src/module/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ impl Module {
/// Accessor to modify type metadata such as documentaiton, fields, variants.
pub fn type_meta<T>(&mut self) -> Result<TypeMut<'_, T>, ContextError>
where
T: Named + TypeOf,
T: ?Sized + Named + TypeOf,
{
let type_hash = T::type_hash();

Expand Down
21 changes: 1 addition & 20 deletions crates/rune/src/modules/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,26 +77,7 @@ pub fn module() -> Result<Module, ContextError> {
m.ty::<Function>()?;

{
m.ty::<Generator<Vm>>()?.docs([
"The return value of a function producing a generator.",
"",
"Functions which contain the `yield` keyword produces generators.",
"",
"# Examples",
"",
"```rune",
"use std::ops::Generator;",
"",
"fn generate() {",
" yield 1;",
" yield 2;",
"}",
"",
"let g = generate();",
"assert!(g is Generator)",
"```",
]);

m.ty::<Generator<Vm>>()?;
m.function_meta(generator_next)?;
m.function_meta(generator_resume)?;
m.function_meta(generator_iter)?;
Expand Down
Loading

0 comments on commit 1204dd4

Please sign in to comment.