twizzler/object/
builder.rs

1use std::{marker::PhantomData, mem::MaybeUninit};
2
3use twizzler_abi::{
4    object::{ObjID, Protections},
5    syscall::{
6        BackingType, CreateTieSpec, LifetimeType, ObjectCreate, ObjectCreateFlags, ObjectSource,
7    },
8};
9use twizzler_rt_abi::{bindings::CREATE_KIND_NEW, object::MapFlags};
10
11use super::{Object, TxObject};
12use crate::{
13    marker::{BaseType, StoreCopy},
14    Result,
15};
16
17/// An object builder, for constructing objects using a builder API.
18#[derive(Clone)]
19pub struct ObjectBuilder<Base: BaseType> {
20    spec: ObjectCreate,
21    src_objs: Vec<ObjectSource>,
22    ties: Vec<CreateTieSpec>,
23    name: Option<String>,
24    _pd: PhantomData<Base>,
25}
26
27impl<Base: BaseType> ObjectBuilder<Base> {
28    /// Make a new object builder.
29    pub fn new(spec: ObjectCreate) -> Self {
30        Self {
31            spec,
32            _pd: PhantomData,
33            name: None,
34            src_objs: Vec::new(),
35            ties: Vec::new(),
36        }
37    }
38
39    /// Make the object persistent.
40    pub fn persist(mut self, persist: bool) -> Self {
41        if persist {
42            self.spec.lt = LifetimeType::Persistent;
43        } else {
44            self.spec.lt = LifetimeType::Volatile;
45        }
46        self
47    }
48    
49    /// Cast the base type.
50    pub fn cast<U: BaseType>(self) -> ObjectBuilder<U> {
51        ObjectBuilder::<U>::new(self.spec)
52    }
53
54    /// Add a Source Object that this new object will copy from.
55    pub fn add_src(mut self, obj_src: ObjectSource) -> Self {
56        self.src_objs.push(obj_src);
57        self
58    }
59
60    /// Add a tie specification for this object creation.
61    pub fn add_tie(mut self, tie: CreateTieSpec) -> Self {
62        self.ties.push(tie);
63        self
64    }
65
66    pub fn named(mut self, name: impl ToString) -> Self {
67        self.name = Some(name.to_string());
68        self
69    }
70}
71
72fn bind_name(id: ObjID, name: &str) -> Result<()> {
73    let create = twizzler_rt_abi::bindings::create_options {
74        id: id.raw(),
75        kind: CREATE_KIND_NEW,
76    };
77    let fd = twizzler_rt_abi::fd::twz_rt_fd_open(name, create, 0)?;
78    twizzler_rt_abi::fd::twz_rt_fd_close(fd);
79    Ok(())
80}
81
82impl<Base: BaseType + StoreCopy> ObjectBuilder<Base> {
83    /// Build an object using the provided base vale.
84    /// # Example
85    /// ```
86    /// # use twizzler::object::ObjectBuilder;
87    /// let builder = ObjectBuilder::default();
88    /// let obj = builder.build(42u32).unwrap();
89    /// ```
90    pub fn build(&self, base: Base) -> Result<Object<Base>> {
91        self.build_inplace(|tx| tx.write(base))
92    }
93}
94
95impl<Base: BaseType> ObjectBuilder<Base> {
96    /// Build an object using the provided constructor function.
97    ///
98    /// The constructor should call the .write() method on the TxObject, and
99    /// return the result.
100    /// # Example
101    /// ```
102    /// # use twizzler::object::ObjectBuilder;
103    /// let builder = ObjectBuilder::default();
104    /// let obj = builder.build_inplace(|tx| tx.write(42u32)).unwrap();
105    /// ```
106    pub fn build_inplace<F>(&self, ctor: F) -> Result<Object<Base>>
107    where
108        F: FnOnce(TxObject<MaybeUninit<Base>>) -> Result<TxObject<Base>>,
109    {
110        let id = twizzler_abi::syscall::sys_object_create(
111            self.spec,
112            self.src_objs.as_slice(),
113            self.ties.as_slice(),
114        )?;
115        let mut flags = MapFlags::READ | MapFlags::WRITE;
116        if self.spec.lt == LifetimeType::Persistent {
117            flags.insert(MapFlags::PERSIST);
118            if let Some(ref name) = self.name {
119                bind_name(id, name)?;
120            }
121        } else {
122            if let Some(ref name) = self.name {
123                tracing::warn!(
124                    "tried to name volatile object at creation time: {} {}",
125                    id,
126                    name
127                );
128            }
129        }
130        let mu_object = unsafe { Object::<MaybeUninit<Base>>::map_unchecked(id, flags) }?;
131        let object = ctor(mu_object.into_tx()?)?;
132        object.into_object()
133    }
134
135    /// Build an object using the provided constructor function.
136    ///
137    /// The constructor should call the .write() method on the TxObject or
138    /// otherwise ensure that it is safe to call .assume_init on the underlying
139    /// MaybeUninit.
140    ///
141    /// # Safety
142    /// The caller must ensure that the base is initialized, see MaybeUninit::assume_init.
143    ///
144    /// # Example
145    /// ```
146    /// # use twizzler::object::ObjectBuilder;
147    /// let builder = ObjectBuilder::default();
148    /// let obj = unsafe {
149    ///     builder
150    ///         .build_ctor(|tx| {
151    ///             tx.write(42u32);
152    ///         })
153    ///         .unwrap()
154    /// };
155    /// ```
156    pub unsafe fn build_ctor<F>(&self, ctor: F) -> Result<Object<Base>>
157    where
158        F: FnOnce(&mut TxObject<MaybeUninit<Base>>),
159    {
160        self.build_inplace(|mut tx| {
161            ctor(&mut tx);
162            Ok(tx.assume_init())
163        })
164    }
165}
166
167impl<Base: BaseType> Default for ObjectBuilder<Base> {
168    fn default() -> Self {
169        Self::new(ObjectCreate::new(
170            BackingType::Normal,
171            LifetimeType::Volatile,
172            None,
173            ObjectCreateFlags::empty(),
174            Protections::all(),
175        ))
176    }
177}
178
179#[cfg(test)]
180mod tests {
181    use super::ObjectBuilder;
182    use crate::{marker::BaseType, object::TypedObject, ptr::InvPtr};
183
184    #[test]
185    fn builder_simple() {
186        let builder = ObjectBuilder::default();
187        let obj = builder.build(42u32).unwrap();
188        let base = obj.base();
189        assert_eq!(*base, 42);
190    }
191
192    struct Foo {
193        ptr: InvPtr<u32>,
194    }
195    impl BaseType for Foo {}
196
197    #[test]
198    fn builder_complex() {
199        let builder = ObjectBuilder::default();
200        let obj_1 = builder.build(42u32).unwrap();
201        let base = obj_1.base_ref();
202        assert_eq!(*base, 42);
203
204        let builder = ObjectBuilder::<Foo>::default();
205        let obj = builder
206            .build_inplace(|tx| {
207                let foo = Foo {
208                    ptr: InvPtr::new(&tx, base)?,
209                };
210                tx.write(foo)
211            })
212            .unwrap();
213        let base_foo = obj.base();
214        let r = unsafe { base_foo.ptr.resolve() };
215        assert_eq!(*r, 42);
216    }
217}