Skip to content

Instantly share code, notes, and snippets.

@dherman
Created March 7, 2016 17:21
Show Gist options
  • Save dherman/5fda1f99cf299588a97b to your computer and use it in GitHub Desktop.
Save dherman/5fda1f99cf299588a97b to your computer and use it in GitHub Desktop.
#[doc(hidden)]
#[macro_export]
macro_rules! class_definition {
( $cls:ident ; $typ: ident ; $allocator:tt ; $mnames:tt ; $mdefs:tt ; init($call:ident) $body:block $($rest:tt)* ) => {
fn allocator_definition($call: $crate::vm::FunctionCall<$crate::js::JsUndefined>) -> $crate::vm::VmResult<$typ> {
$body
}
class_definition!($cls ; $typ ; allocator_definition ; $mnames ; $mdefs ; $($rest)*);
};
( $cls:ident ; $typ: ident ; $allocator:tt ; ($($mname:tt)*) ; ($($mdef:tt)*) ; method $name:ident($call:ident) $body:block $($rest:tt)* ) => {
fn method_definition($call: $crate::vm::FunctionCall<$cls>) -> $crate::vm::JsResult<$crate::js::JsValue> {
$body
}
class_definition!($cls ; $typ ; $allocator ; ($($mname)* $name) ; ($($mdef)* method_definition) ; $($rest)*);
};
( $cls:ident ; $typ: ident ; $allocator:ident ; ($($mname:ident)*) ; ($($mdef:ident)*) ; $($rest:tt)* ) => {
impl $crate::js::class::Class for $cls {
type Internals = $typ;
fn setup<'a, T: $crate::scope::Scope<'a>>(_: &mut T) -> $crate::vm::VmResult<$crate::js::class::ClassDescriptor<'a, Self>> {
::std::result::Result::Ok(Self::describe(stringify!($typ), $allocator)
$(.method(stringify!($mname), $mdef))*)
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_managed {
($cls:ident) => {
impl $crate::mem::Managed for $cls {
fn to_raw(self) -> $crate::sys::raw::Local {
let $cls(raw) = self;
raw
}
fn from_raw(raw: $crate::sys::raw::Local) -> Self {
$cls(raw)
}
}
}
}
/// Declare custom native JavaScript types with Rust implementations.
///
/// Example:
///
/// ```rust
/// pub struct Greeter {
/// greeting: String
/// }
///
/// types! {
///
/// /// A class for generating greeting strings.
/// pub class JsGreeter for Greeter {
/// init(call) {
/// let scope = call.scope;
/// let greeting = try!(try!(call.arguments.require(scope, 0)).to_string(scope)).value();
/// Ok(Greeter {
/// greeting: greeting
/// })
/// }
///
/// method hello(call) {
/// let scope = call.scope;
/// let name = try!(try!(call.arguments.require(scope, 0)).to_string(scope)).value();
/// let msg = vm::lock(call.arguments.this(scope), |greeter| {
/// format!("{}, {}!", greeter.greeting, name)
/// });
/// Ok(try!(JsString::new_or_throw(scope, &msg[..])).upcast())
/// }
/// }
///
/// }
/// ```
#[macro_export]
macro_rules! types {
{ $(#[$attr:meta])* pub class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
#[derive(Copy, Clone)]
#[repr(C)]
$(#[$attr])*
pub struct $cls($crate::sys::raw::Local);
impl_managed!($cls);
class_definition!($cls ; $typ ; () ; () ; () ; $($body)*);
types! { $($rest)* }
};
{ $(#[$attr:meta])* class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
#[derive(Copy, Clone)]
#[repr(C)]
$(#[$attr])*
struct $cls($crate::sys::raw::Local);
impl_managed!($cls);
class_definition!($cls ; $typ ; () ; () ; () ; $($body)*);
types! { $($rest)* }
};
{ } => { };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment