use crate::{ __private, BindError, WebApiObject, define_to_string_tag, set_interface_prototype, v8, }; /// Binds a Web API constructor/prototype pair onto a V8 global object. /// /// Implementations are generated by `#[derive(WebApiInterface)]`. The generated /// binding creates the prototype object, links the optional parent prototype, /// installs declared prototype methods, creates the constructor function, and /// publishes it on the provided global object. pub trait WebApiInterfaceDeclaration { const NAME: &'static str; const PARENT: Option<&'static str>; fn bind<'s>( &self, scope: &mut v8::PinScope<'s, '_>, global: v8::Local<'s, v8::Object>, ) -> Result, BindError>; } /// 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 Web API object instance or object-like shell. /// /// 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 declared interface prototype and object /// tag. `bind` creates a fresh V8 object and then delegates to `bind_into`. pub trait WebApiObjectDeclaration<'s> { const INTERFACE: &'static str; const OWN_TO_STRING_TAG: Option<&'static str>; 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> { let _ = set_interface_prototype(scope, object, Self::INTERFACE); if let Some(tag) = Self::OWN_TO_STRING_TAG { define_to_string_tag(scope, object, tag); } self.initialize(scope, object) } fn bind( &self, scope: &mut v8::PinScope<'s, '_>, ) -> Result, BindError> { let object = v8::Object::new(scope); self.bind_into(scope, object)?; Ok(object) } } /// Declares the descriptor object returned by native named/indexed property /// descriptor interceptors for data properties. #[derive(WebApiObject)] #[webapi( interface = "Object", 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() } }