use std::collections::HashSet;
use crate::model::*;
pub struct InterfaceBuilder<'a> {
lib: &'a mut LibraryBuilder,
name: Name,
callbacks: Vec<CallbackFunction<Unvalidated>>,
callback_names: HashSet<String>,
doc: Doc<Unvalidated>,
}
impl<'a> InterfaceBuilder<'a> {
pub(crate) fn new(lib: &'a mut LibraryBuilder, name: Name, doc: Doc<Unvalidated>) -> Self {
Self {
lib,
name,
callbacks: Vec::new(),
callback_names: Default::default(),
doc,
}
}
pub fn begin_callback<T: IntoName, D: Into<Doc<Unvalidated>>>(
mut self,
name: T,
doc: D,
) -> BindResult<CallbackFunctionBuilder<'a>> {
let name = name.into_name()?;
self.check_unique_callback_name(&name)?;
Ok(CallbackFunctionBuilder::new(self, name, doc.into()))
}
pub fn build_sync(self) -> BindResult<SynchronousInterface> {
let (handle, lib) = self.build(InterfaceCategory::Synchronous);
lib.add_statement(Statement::InterfaceDefinition(InterfaceType::Synchronous(
handle.clone(),
)))?;
Ok(SynchronousInterface { inner: handle })
}
pub fn build_async(self) -> BindResult<AsynchronousInterface> {
let (handle, lib) = self.build(InterfaceCategory::Asynchronous);
lib.add_statement(Statement::InterfaceDefinition(InterfaceType::Asynchronous(
handle.clone(),
)))?;
Ok(AsynchronousInterface { inner: handle })
}
pub(crate) fn build(
self,
mode: InterfaceCategory,
) -> (InterfaceHandle, &'a mut LibraryBuilder) {
let handle = Handle::new(Interface {
name: self.name,
mode,
callbacks: self.callbacks,
doc: self.doc,
settings: self.lib.clone_settings(),
});
(handle, self.lib)
}
fn check_unique_callback_name(&mut self, name: &Name) -> BindResult<()> {
if name == &self.lib.settings().interface.destroy_func_name {
return Err(BindingErrorVariant::InterfaceMethodWithReservedName {
name: self.lib.settings().interface.destroy_func_name.clone(),
}
.into());
}
if name == &self.lib.settings().interface.context_variable_name.clone() {
return Err(BindingErrorVariant::InterfaceMethodWithReservedName {
name: self.lib.settings().interface.context_variable_name.clone(),
}
.into());
}
if self.callback_names.insert(name.to_string()) {
Ok(())
} else {
Err(BindingErrorVariant::InterfaceDuplicateCallbackName {
interface_name: self.name.clone(),
callback_name: name.clone(),
}
.into())
}
}
}
pub struct CallbackFunctionBuilder<'a> {
builder: InterfaceBuilder<'a>,
name: Name,
functional_transform: FunctionalTransform,
return_type: OptionalReturnType<CallbackReturnValue, Unvalidated>,
default_implementation: Option<DefaultCallbackReturnValue>,
arguments: Vec<Arg<CallbackArgument, Unvalidated>>,
doc: Doc<Unvalidated>,
}
impl<'a> CallbackFunctionBuilder<'a> {
pub(crate) fn new(builder: InterfaceBuilder<'a>, name: Name, doc: Doc<Unvalidated>) -> Self {
Self {
builder,
name,
functional_transform: FunctionalTransform::No,
return_type: OptionalReturnType::new(),
default_implementation: None,
arguments: Vec::new(),
doc,
}
}
#[must_use]
pub fn enable_functional_transform(mut self) -> Self {
self.functional_transform = FunctionalTransform::Yes;
self
}
pub fn param<S: IntoName, D: Into<DocString<Unvalidated>>, P: Into<CallbackArgument>>(
mut self,
name: S,
arg_type: P,
doc: D,
) -> BindResult<Self> {
let arg_type = arg_type.into();
let name = name.into_name()?;
if name == self.builder.lib.settings().interface.context_variable_name {
return Err(
BindingErrorVariant::CallbackMethodArgumentWithReservedName {
name: self
.builder
.lib
.settings()
.interface
.context_variable_name
.clone(),
}
.into(),
);
}
self.arguments.push(Arg::new(arg_type, name, doc.into()));
Ok(self)
}
pub fn returns<T: Into<CallbackReturnValue>, D: Into<DocString<Unvalidated>>>(
mut self,
t: T,
d: D,
) -> BindResult<Self> {
self.return_type.set(&self.name, t.into(), d.into())?;
Ok(self)
}
pub fn returns_with_default<
T: Into<DefaultCallbackReturnValue>,
D: Into<DocString<Unvalidated>>,
>(
self,
t: T,
d: D,
) -> BindResult<Self> {
let default: DefaultCallbackReturnValue = t.into();
let mut ret = if let Some(return_type) = default.get_callback_return_value() {
self.returns(return_type, d)?
} else {
self
};
ret.default_implementation = Some(default);
Ok(ret)
}
pub fn returns_nothing_by_default(mut self) -> BindResult<Self> {
if self.return_type.is_some() {
return Err(BindingErrorVariant::ReturnTypeAlreadyDefined {
func_name: self.name,
}
.into());
}
self.default_implementation = Some(DefaultCallbackReturnValue::Void);
Ok(self)
}
pub fn end_callback(mut self) -> BindResult<InterfaceBuilder<'a>> {
let cb = CallbackFunction {
name: self.name,
functional_transform: self.functional_transform,
return_type: self.return_type,
default_implementation: self.default_implementation,
arguments: self.arguments,
doc: self.doc,
};
self.builder.callbacks.push(cb);
Ok(self.builder)
}
}