oo_bindgen/model/builder/
class.rs

1use crate::model::*;
2
3pub struct ClassBuilder<'a> {
4    lib: &'a mut LibraryBuilder,
5    declaration: ClassDeclarationHandle,
6    constructor: Option<ClassConstructor<Unvalidated>>,
7    destructor: Option<ClassDestructor<Unvalidated>>,
8    methods: Vec<Method<Unvalidated>>,
9    static_methods: Vec<StaticMethod<Unvalidated>>,
10    async_methods: Vec<FutureMethod<Unvalidated>>,
11    doc: Option<Doc<Unvalidated>>,
12    destruction_mode: DestructionMode,
13}
14
15impl<'a> ClassBuilder<'a> {
16    pub(crate) fn new(lib: &'a mut LibraryBuilder, declaration: ClassDeclarationHandle) -> Self {
17        Self {
18            lib,
19            declaration,
20            constructor: None,
21            destructor: None,
22            methods: Vec::new(),
23            static_methods: Vec::new(),
24            async_methods: Vec::new(),
25            doc: None,
26            destruction_mode: DestructionMode::Automatic,
27        }
28    }
29
30    pub fn doc<D: Into<Doc<Unvalidated>>>(mut self, doc: D) -> BindResult<Self> {
31        match self.doc {
32            None => {
33                self.doc = Some(doc.into());
34                Ok(self)
35            }
36            Some(_) => Err(BindingErrorVariant::DocAlreadyDefined {
37                symbol_name: self.declaration.name.clone(),
38            }
39            .into()),
40        }
41    }
42
43    pub fn constructor(mut self, constructor: ClassConstructor<Unvalidated>) -> BindResult<Self> {
44        // make sure the method is defined for this class
45        self.check_class(&constructor.function.name, constructor.class.clone())?;
46
47        if self.constructor.is_some() {
48            return Err(BindingErrorVariant::ConstructorAlreadyDefined {
49                handle: self.declaration,
50            }
51            .into());
52        }
53
54        self.constructor = Some(constructor);
55
56        Ok(self)
57    }
58
59    pub fn destructor(mut self, destructor: ClassDestructor<Unvalidated>) -> BindResult<Self> {
60        if self.destructor.is_some() {
61            return Err(BindingErrorVariant::DestructorAlreadyDefined {
62                handle: self.declaration,
63            }
64            .into());
65        }
66
67        // make sure the method is defined for this class
68        self.check_class(&destructor.function.name, destructor.class.clone())?;
69
70        self.destructor = Some(destructor);
71
72        Ok(self)
73    }
74
75    pub fn method(mut self, method: Method<Unvalidated>) -> BindResult<Self> {
76        // make sure the method is defined for this class
77        self.check_class(&method.name, method.associated_class.clone())?;
78
79        self.methods.push(method);
80
81        Ok(self)
82    }
83
84    pub fn static_method(mut self, method: StaticMethod<Unvalidated>) -> BindResult<Self> {
85        self.static_methods.push(method);
86        Ok(self)
87    }
88
89    fn check_class(&self, name: &Name, other: ClassDeclarationHandle) -> BindResult<()> {
90        if self.declaration != other {
91            return Err(BindingErrorVariant::ClassMemberWrongAssociatedClass {
92                name: name.clone(),
93                declared: other,
94                added_to: self.declaration.clone(),
95            }
96            .into());
97        }
98        Ok(())
99    }
100
101    pub fn async_method(mut self, method: FutureMethod<Unvalidated>) -> BindResult<Self> {
102        self.check_class(&method.name, method.associated_class.clone())?;
103
104        self.async_methods.push(method);
105
106        Ok(self)
107    }
108
109    pub fn custom_destroy<T: IntoName>(mut self, name: T) -> BindResult<Self> {
110        if self.destructor.is_none() {
111            return Err(BindingErrorVariant::NoDestructorForManualDestruction {
112                handle: self.declaration,
113            }
114            .into());
115        }
116
117        self.destruction_mode = DestructionMode::Custom(name.into_name()?);
118        Ok(self)
119    }
120
121    pub fn disposable_destroy(mut self) -> BindResult<Self> {
122        if self.destructor.is_none() {
123            return Err(BindingErrorVariant::NoDestructorForManualDestruction {
124                handle: self.declaration,
125            }
126            .into());
127        }
128
129        self.destruction_mode = DestructionMode::Dispose;
130        Ok(self)
131    }
132
133    pub fn build(self) -> BindResult<ClassHandle> {
134        let doc = match self.doc {
135            Some(doc) => doc,
136            None => {
137                return Err(BindingErrorVariant::DocNotDefined {
138                    symbol_name: self.declaration.name.clone(),
139                }
140                .into())
141            }
142        };
143
144        let handle = Handle::new(Class {
145            declaration: self.declaration.clone(),
146            constructor: self.constructor,
147            destructor: self.destructor,
148            methods: self.methods,
149            static_methods: self.static_methods,
150            future_methods: self.async_methods,
151            doc,
152            destruction_mode: self.destruction_mode,
153            settings: self.lib.clone_settings(),
154        });
155
156        self.lib
157            .add_statement(Statement::ClassDefinition(handle.clone()))?;
158
159        Ok(handle)
160    }
161}
162
163pub struct StaticClassBuilder<'a> {
164    lib: &'a mut LibraryBuilder,
165    name: Name,
166    static_methods: Vec<StaticMethod<Unvalidated>>,
167    doc: OptionalDoc,
168}
169
170impl<'a> StaticClassBuilder<'a> {
171    pub(crate) fn new(lib: &'a mut LibraryBuilder, name: Name) -> Self {
172        Self {
173            lib,
174            name: name.clone(),
175            static_methods: Vec::new(),
176            doc: OptionalDoc::new(name),
177        }
178    }
179
180    pub fn doc<D: Into<Doc<Unvalidated>>>(mut self, doc: D) -> BindResult<Self> {
181        self.doc.set(doc.into())?;
182        Ok(self)
183    }
184
185    pub fn static_method(mut self, method: StaticMethod<Unvalidated>) -> BindResult<Self> {
186        self.static_methods.push(method);
187        Ok(self)
188    }
189
190    pub fn build(self) -> BindResult<StaticClassHandle> {
191        let handle = Handle::new(StaticClass {
192            name: self.name,
193            static_methods: self.static_methods,
194            doc: self.doc.extract()?,
195        });
196
197        self.lib
198            .add_statement(Statement::StaticClassDefinition(handle.clone()))?;
199
200        Ok(handle)
201    }
202}