twizzler/object/
builder.rs1use std::{ffi::c_char, marker::PhantomData, mem::MaybeUninit};
2
3use twizzler_rt_abi::{
4 bindings::{object_source, object_tie},
5 error::RawTwzError,
6 object::{
7 BackingType, CreateTieSpec, LifetimeType, MapFlags, ObjectCreate, ObjectCreateFlags,
8 ObjectSource, Protections,
9 },
10};
11
12use super::{Object, TxObject};
13use crate::{
14 marker::{BaseType, StoreCopy},
15 Result,
16};
17
18#[derive(Clone)]
20pub struct ObjectBuilder<Base: BaseType> {
21 spec: ObjectCreate,
22 src_objs: Vec<object_source>,
23 ties: Vec<object_tie>,
24 name: Option<String>,
25 _pd: PhantomData<Base>,
26}
27
28impl<Base: BaseType> ObjectBuilder<Base> {
29 pub fn new(spec: ObjectCreate) -> Self {
31 Self {
32 spec,
33 _pd: PhantomData,
34 name: None,
35 src_objs: Vec::new(),
36 ties: Vec::new(),
37 }
38 }
39
40 pub fn persist(mut self, persist: bool) -> Self {
42 if persist {
43 self.spec.lt = LifetimeType::Persistent;
44 } else {
45 self.spec.lt = LifetimeType::Volatile;
46 }
47 self
48 }
49
50 pub fn cast<U: BaseType>(self) -> ObjectBuilder<U> {
52 ObjectBuilder::<U>::new(self.spec)
53 }
54
55 pub fn add_src(mut self, obj_src: ObjectSource) -> Self {
57 self.src_objs.push(obj_src.into());
58 self
59 }
60
61 pub fn add_tie(mut self, tie: CreateTieSpec) -> Self {
63 self.ties.push(tie.into());
64 self
65 }
66
67 pub fn named(mut self, name: impl ToString) -> Self {
68 self.name = Some(name.to_string());
69 self
70 }
71}
72
73impl<Base: BaseType + StoreCopy> ObjectBuilder<Base> {
74 pub fn build(&self, base: Base) -> Result<Object<Base>> {
82 self.build_inplace(|tx| tx.write(base))
83 }
84}
85
86impl<Base: BaseType> ObjectBuilder<Base> {
87 pub fn build_inplace<F>(&self, ctor: F) -> Result<Object<Base>>
98 where
99 F: FnOnce(TxObject<MaybeUninit<Base>>) -> Result<TxObject<Base>>,
100 {
101 let id = unsafe {
102 twizzler_rt_abi::bindings::twz_rt_create_object(
103 &self.spec.into(),
104 self.src_objs.as_slice().as_ptr(),
105 self.src_objs.len(),
106 self.ties.as_slice().as_ptr(),
107 self.ties.len(),
108 self.name
109 .as_ref()
110 .map(|s| s.as_ptr().cast::<c_char>())
111 .unwrap_or(core::ptr::null())
112 .cast(),
113 self.name.as_ref().map(|s| s.len()).unwrap_or(0),
114 )
115 };
116 if id.err != 0 {
117 return Err(RawTwzError::new(id.err).error());
118 }
119 let id = id.val.into();
120 let mut flags = MapFlags::READ | MapFlags::WRITE;
121 if self.spec.lt == LifetimeType::Persistent {
122 flags.insert(MapFlags::PERSIST);
123 } else {
124 if let Some(ref name) = self.name {
125 tracing::warn!(
126 "tried to name volatile object at creation time: {} {}",
127 id,
128 name
129 );
130 }
131 }
132 let mu_object = unsafe { Object::<MaybeUninit<Base>>::map_unchecked(id, flags) }?;
133 let object = ctor(mu_object.into_tx()?)?;
134 object.into_object()
135 }
136
137 pub unsafe fn build_ctor<F>(&self, ctor: F) -> Result<Object<Base>>
159 where
160 F: FnOnce(&mut TxObject<MaybeUninit<Base>>),
161 {
162 self.build_inplace(|mut tx| {
163 ctor(&mut tx);
164 Ok(tx.assume_init())
165 })
166 }
167}
168
169impl<Base: BaseType> Default for ObjectBuilder<Base> {
170 fn default() -> Self {
171 Self::new(ObjectCreate::new(
172 BackingType::Normal,
173 LifetimeType::Volatile,
174 None,
175 ObjectCreateFlags::empty(),
176 Protections::all(),
177 ))
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::ObjectBuilder;
184 use crate::{marker::BaseType, object::TypedObject, ptr::InvPtr};
185
186 #[test]
187 fn builder_simple() {
188 let builder = ObjectBuilder::default();
189 let obj = builder.build(42u32).unwrap();
190 let base = obj.base();
191 assert_eq!(*base, 42);
192 }
193
194 struct Foo {
195 ptr: InvPtr<u32>,
196 }
197 impl BaseType for Foo {}
198
199 #[test]
200 fn builder_complex() {
201 let builder = ObjectBuilder::default();
202 let obj_1 = builder.build(42u32).unwrap();
203 let base = obj_1.base_ref();
204 assert_eq!(*base, 42);
205
206 let builder = ObjectBuilder::<Foo>::default();
207 let obj = builder
208 .build_inplace(|tx| {
209 let foo = Foo {
210 ptr: InvPtr::new(&tx, base)?,
211 };
212 tx.write(foo)
213 })
214 .unwrap();
215 let base_foo = obj.base();
216 let r = unsafe { base_foo.ptr.resolve() };
217 assert_eq!(*r, 42);
218 }
219}