Files
moli/moli-webapi-declare/src/declaration.rs

138 lines
4.4 KiB
Rust

use crate::{__private, BindError, WebApiObject, v8};
/// Binds a constructor-backed Web API V8 function template.
///
/// Implementations are generated by `#[derive(WebApiFunctionTemplate)]`. The
/// generated binding creates a `FunctionTemplate`, sets its class name, and
/// installs declared static methods and constants onto the constructor template
/// and declared instance methods, intrinsic data properties, and constants onto
/// the prototype template. This is separate from `WebApiObjectDeclaration`
/// because template installation happens before constructor/prototype objects
/// exist in a V8 context.
pub trait WebApiFunctionTemplateDeclaration {
const NAME: &'static str;
fn build<'s>(scope: &mut v8::PinScope<'s, '_, ()>) -> v8::Local<'s, v8::FunctionTemplate>;
fn initialize_template<'s>(
scope: &mut v8::PinScope<'s, '_, ()>,
template: v8::Local<'s, v8::FunctionTemplate>,
);
fn initialize_prototype_template<'s>(
scope: &mut v8::PinScope<'s, '_, ()>,
prototype: v8::Local<'s, v8::ObjectTemplate>,
);
}
/// Binds a native instance, plain object, or shared initialization fragment.
///
/// Implementations are generated by `#[derive(WebApiObject)]`. `initialize`
/// installs only the fields that are explicitly declared as properties, methods,
/// hidden properties, private slots, prototype values, or toStringTag values.
/// `bind_into` additionally applies the role's prototype policy and declared object
/// tag. `bind` creates a fresh V8 object and then delegates to `bind_into`.
pub trait WebApiObjectDeclaration<'s> {
fn initialize(
&self,
scope: &mut v8::PinScope<'s, '_>,
object: v8::Local<'s, v8::Object>,
) -> Result<(), BindError>;
fn bind_into(
&self,
scope: &mut v8::PinScope<'s, '_>,
object: v8::Local<'s, v8::Object>,
) -> Result<(), BindError>;
fn bind(
&self,
scope: &mut v8::PinScope<'s, '_>,
) -> Result<v8::Local<'s, v8::Object>, BindError>;
}
/// Declares the descriptor object returned by native named/indexed property
/// descriptor interceptors for data properties.
#[derive(WebApiObject)]
#[webapi(plain, data_properties, enumerable, no_dynamic_constructor)]
pub struct DataPropertyDescriptorDeclaration<'scope> {
value: v8::Local<'scope, v8::Value>,
enumerable: bool,
configurable: bool,
writable: bool,
}
impl<'scope> DataPropertyDescriptorDeclaration<'scope> {
pub fn new(value: v8::Local<'scope, v8::Value>, writable: bool, enumerable: bool) -> Self {
Self {
value,
enumerable,
configurable: true,
writable,
}
}
}
/// Small builder for plain object literals that are assembled imperatively.
///
/// Prefer `#[derive(WebApiObject)]` when the shape is known from a Rust struct.
/// This helper remains useful for dynamic copies where the property set is only
/// known at runtime, such as collecting selected fields from another V8 object.
pub struct ObjectLiteralDeclaration<'s> {
object: v8::Local<'s, v8::Object>,
}
impl<'s> ObjectLiteralDeclaration<'s> {
pub fn bind(scope: &mut v8::PinScope<'s, '_>) -> Self {
Self {
object: v8::Object::new(scope),
}
}
pub fn set_value_property(
&self,
scope: &mut v8::PinScope<'s, '_>,
name: v8::Local<'s, v8::Name>,
value: v8::Local<'s, v8::Value>,
) {
let _ = self.object.create_data_property(scope, name, value);
}
pub fn set_string_property(
&self,
scope: &mut v8::PinScope<'s, '_>,
name: &str,
value: v8::Local<'s, v8::Value>,
) {
if let Some(name) = __private::v8_string(scope, name) {
self.set_value_property(scope, name.into(), value);
}
}
pub fn copy_string_property(
&self,
scope: &mut v8::PinScope<'s, '_>,
source: v8::Local<'s, v8::Object>,
name: &str,
) {
let Some(name) = __private::v8_string(scope, name) else {
return;
};
if let Some(value) = source.get(scope, name.into()) {
self.set_value_property(scope, name.into(), value);
}
}
pub fn as_object(&self) -> v8::Local<'s, v8::Object> {
self.object
}
pub fn into_object(self) -> v8::Local<'s, v8::Object> {
self.object
}
pub fn into_value(self) -> v8::Local<'s, v8::Value> {
self.object.into()
}
}