Skip to content

Commit

Permalink
allow to derive protocols with Any
Browse files Browse the repository at this point in the history
  • Loading branch information
ModProg committed Aug 3, 2023
1 parent 2f0e7af commit 5cf35bc
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 3 deletions.
6 changes: 5 additions & 1 deletion crates/rune-macros/src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ impl Derive {
let generics = &self.input.generics;
let mut installers = Vec::new();

let Ok(()) = expand_install_with(&cx, &self.input, &tokens, &attr, generics, &mut installers) else {
let Ok(()) =
expand_install_with(&cx, &self.input, &tokens, &attr, generics, &mut installers)
else {
return Err(cx.errors.into_inner());
};

Expand Down Expand Up @@ -152,6 +154,8 @@ pub(crate) fn expand_install_with(
}
}

installers.extend(attr.protocols.iter().map(|protocol| protocol.expand()));

if let Some(install_with) = &attr.install_with {
installers.push(quote_spanned! { input.span() =>
#install_with(module)?;
Expand Down
66 changes: 64 additions & 2 deletions crates/rune-macros/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::cell::RefCell;
use crate::internals::*;
use proc_macro2::Span;
use proc_macro2::TokenStream;
use quote::quote_spanned;
use quote::{quote, ToTokens};
use quote::{quote, quote_spanned, ToTokens};
use syn::parse::Parse;
use syn::parse::ParseStream;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned as _;
Expand Down Expand Up @@ -74,6 +74,8 @@ pub(crate) struct TypeAttr {
pub(crate) item: Option<syn::Path>,
/// `#[rune(constructor)]`.
pub(crate) constructor: bool,
/// Protocols to "derive"
pub(crate) protocols: Vec<TypeProtocol>,
/// Parsed documentation.
pub(crate) docs: Vec<syn::Expr>,
}
Expand Down Expand Up @@ -113,6 +115,60 @@ pub(crate) struct FieldProtocol {
custom: Option<syn::Path>,
}

pub(crate) struct TypeProtocol {
protocol: syn::Ident,
handler: Option<syn::Path>,
}

impl TypeProtocol {
pub fn expand(&self) -> TokenStream {
if let Some(handler) = &self.handler {
let protocol = &self.protocol;
return quote_spanned! {protocol.span()=>
module.associated_function(rune::runtime::Protocol::#protocol, #handler)?;
};
}
match self.protocol.to_string().as_str() {
"ADD" => quote_spanned! {self.protocol.span()=>
module.associated_function(rune::runtime::Protocol::ADD, |this: Self, other: Self| this + other)?;
},
"STRING_DISPLAY" => quote_spanned! {self.protocol.span()=>
module.associated_function(rune::runtime::Protocol::STRING_DISPLAY, |this: &Self, buf: &mut String| {
use ::std::fmt::Write as _;
::std::write!(buf, "{this}")
})?;
},
"STRING_DEBUG" => quote_spanned! {self.protocol.span()=>
module.associated_function(rune::runtime::Protocol::STRING_DEBUG, |this: &Self, buf: &mut String| {
use ::std::fmt::Write as _;
::std::write!(buf, "{this:?}")
})?;
},
_ => syn::Error::new_spanned(
&self.protocol,
format!(
"`{}` is not a protocol supported for automatic generation on a type",
self.protocol
),
)
.to_compile_error(),
}
}
}

impl Parse for TypeProtocol {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(Self {
protocol: input.parse()?,
handler: if input.parse::<Token![=]>().is_ok() {
Some(input.parse()?)
} else {
None
},
})
}
}

#[derive(Default)]
pub(crate) struct Context {
pub(crate) errors: RefCell<Vec<syn::Error>>,
Expand Down Expand Up @@ -445,6 +501,12 @@ impl Context {
attr.install_with = Some(parse_path_compat(meta.input)?);
} else if meta.path == CONSTRUCTOR {
attr.constructor = true;
} else if meta.path == PROTOCOLS {
// Parse `#[rune(protocols(<protocol>,*))]`
let protocols;
syn::parenthesized!(protocols in meta.input);
attr.protocols
.extend(protocols.parse_terminated(TypeProtocol::parse, Token![,])?);
} else {
return Err(syn::Error::new_spanned(
&meta.path,
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 @@ -19,6 +19,7 @@ pub const NAME: Symbol = Symbol("name");
pub const ITEM: Symbol = Symbol("item");
pub const MODULE: Symbol = Symbol("module");
pub const INSTALL_WITH: Symbol = Symbol("install_with");
pub const PROTOCOLS: Symbol = Symbol("protocols");

pub const CONSTRUCTOR: Symbol = Symbol("constructor");
pub const GET: Symbol = Symbol("get");
Expand Down

0 comments on commit 5cf35bc

Please sign in to comment.