oo_bindgen/model/builder/
interface.rs

1use std::collections::HashSet;
2
3use crate::model::*;
4
5pub struct InterfaceBuilder<'a> {
6    lib: &'a mut LibraryBuilder,
7    name: Name,
8    callbacks: Vec<CallbackFunction<Unvalidated>>,
9    callback_names: HashSet<String>,
10    doc: Doc<Unvalidated>,
11}
12
13impl<'a> InterfaceBuilder<'a> {
14    pub(crate) fn new(lib: &'a mut LibraryBuilder, name: Name, doc: Doc<Unvalidated>) -> Self {
15        Self {
16            lib,
17            name,
18            callbacks: Vec::new(),
19            callback_names: Default::default(),
20            doc,
21        }
22    }
23
24    pub fn begin_callback<T: IntoName, D: Into<Doc<Unvalidated>>>(
25        mut self,
26        name: T,
27        doc: D,
28    ) -> BindResult<CallbackFunctionBuilder<'a>> {
29        let name = name.into_name()?;
30        self.check_unique_callback_name(&name)?;
31        Ok(CallbackFunctionBuilder::new(self, name, doc.into()))
32    }
33
34    /// Build the interface and mark it as only used in a synchronous context.
35    ///
36    /// A synchronous interface is one that is invoked only during a function call which
37    /// takes it as an argument. The Rust backend will NOT generate `Send` and `Sync`
38    /// implementations so that it be cannot be transferred across thread boundaries.
39    pub fn build_sync(self) -> BindResult<SynchronousInterface> {
40        let (handle, lib) = self.build(InterfaceCategory::Synchronous);
41        lib.add_statement(Statement::InterfaceDefinition(InterfaceType::Synchronous(
42            handle.clone(),
43        )))?;
44        Ok(SynchronousInterface { inner: handle })
45    }
46
47    /// Build the interface and mark it as used in an asynchronous context.
48    ///
49    /// An asynchronous interface is one that is invoked some time after it is
50    /// passed as a function argument. The Rust backend will mark the C representation
51    /// of this interface as `Send` and `Sync` so that it be transferred across thread
52    /// boundaries.
53    pub fn build_async(self) -> BindResult<AsynchronousInterface> {
54        let (handle, lib) = self.build(InterfaceCategory::Asynchronous);
55        lib.add_statement(Statement::InterfaceDefinition(InterfaceType::Asynchronous(
56            handle.clone(),
57        )))?;
58        Ok(AsynchronousInterface { inner: handle })
59    }
60
61    pub(crate) fn build(
62        self,
63        mode: InterfaceCategory,
64    ) -> (InterfaceHandle, &'a mut LibraryBuilder) {
65        let handle = Handle::new(Interface {
66            name: self.name,
67            mode,
68            callbacks: self.callbacks,
69            doc: self.doc,
70            settings: self.lib.clone_settings(),
71        });
72
73        (handle, self.lib)
74    }
75
76    fn check_unique_callback_name(&mut self, name: &Name) -> BindResult<()> {
77        if name == &self.lib.settings().interface.destroy_func_name {
78            return Err(BindingErrorVariant::InterfaceMethodWithReservedName {
79                name: self.lib.settings().interface.destroy_func_name.clone(),
80            }
81            .into());
82        }
83
84        if name == &self.lib.settings().interface.context_variable_name.clone() {
85            return Err(BindingErrorVariant::InterfaceMethodWithReservedName {
86                name: self.lib.settings().interface.context_variable_name.clone(),
87            }
88            .into());
89        }
90
91        if self.callback_names.insert(name.to_string()) {
92            Ok(())
93        } else {
94            Err(BindingErrorVariant::InterfaceDuplicateCallbackName {
95                interface_name: self.name.clone(),
96                callback_name: name.clone(),
97            }
98            .into())
99        }
100    }
101}
102
103pub struct CallbackFunctionBuilder<'a> {
104    builder: InterfaceBuilder<'a>,
105    name: Name,
106    functional_transform: FunctionalTransform,
107    return_type: OptionalReturnType<CallbackReturnValue, Unvalidated>,
108    default_implementation: Option<DefaultCallbackReturnValue>,
109    arguments: Vec<Arg<CallbackArgument, Unvalidated>>,
110    doc: Doc<Unvalidated>,
111}
112
113impl<'a> CallbackFunctionBuilder<'a> {
114    pub(crate) fn new(builder: InterfaceBuilder<'a>, name: Name, doc: Doc<Unvalidated>) -> Self {
115        Self {
116            builder,
117            name,
118            functional_transform: FunctionalTransform::No,
119            return_type: OptionalReturnType::new(),
120            default_implementation: None,
121            arguments: Vec::new(),
122            doc,
123        }
124    }
125
126    #[must_use]
127    pub fn enable_functional_transform(mut self) -> Self {
128        self.functional_transform = FunctionalTransform::Yes;
129        self
130    }
131
132    pub fn param<S: IntoName, D: Into<DocString<Unvalidated>>, P: Into<CallbackArgument>>(
133        mut self,
134        name: S,
135        arg_type: P,
136        doc: D,
137    ) -> BindResult<Self> {
138        let arg_type = arg_type.into();
139        let name = name.into_name()?;
140
141        if name == self.builder.lib.settings().interface.context_variable_name {
142            return Err(
143                BindingErrorVariant::CallbackMethodArgumentWithReservedName {
144                    name: self
145                        .builder
146                        .lib
147                        .settings()
148                        .interface
149                        .context_variable_name
150                        .clone(),
151                }
152                .into(),
153            );
154        }
155
156        self.arguments.push(Arg::new(arg_type, name, doc.into()));
157        Ok(self)
158    }
159
160    pub fn returns<T: Into<CallbackReturnValue>, D: Into<DocString<Unvalidated>>>(
161        mut self,
162        t: T,
163        d: D,
164    ) -> BindResult<Self> {
165        self.return_type.set(&self.name, t.into(), d.into())?;
166        Ok(self)
167    }
168
169    pub fn returns_with_default<
170        T: Into<DefaultCallbackReturnValue>,
171        D: Into<DocString<Unvalidated>>,
172    >(
173        self,
174        t: T,
175        d: D,
176    ) -> BindResult<Self> {
177        let default: DefaultCallbackReturnValue = t.into();
178
179        let mut ret = if let Some(return_type) = default.get_callback_return_value() {
180            // first, try to set the return type to ensure it hasn't previously been set
181            self.returns(return_type, d)?
182        } else {
183            self
184        };
185
186        ret.default_implementation = Some(default);
187
188        Ok(ret)
189    }
190
191    pub fn returns_nothing_by_default(mut self) -> BindResult<Self> {
192        // return type should not already be defined
193        if self.return_type.is_some() {
194            return Err(BindingErrorVariant::ReturnTypeAlreadyDefined {
195                func_name: self.name,
196            }
197            .into());
198        }
199
200        self.default_implementation = Some(DefaultCallbackReturnValue::Void);
201
202        Ok(self)
203    }
204
205    pub fn end_callback(mut self) -> BindResult<InterfaceBuilder<'a>> {
206        let cb = CallbackFunction {
207            name: self.name,
208            functional_transform: self.functional_transform,
209            return_type: self.return_type,
210            default_implementation: self.default_implementation,
211            arguments: self.arguments,
212            doc: self.doc,
213        };
214
215        self.builder.callbacks.push(cb);
216        Ok(self.builder)
217    }
218}