twizzler/object/
builder.rs1use 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 object::RawObject,
15 Result,
16};
17
18#[derive(Clone)]
20pub struct ObjectBuilder<Base: BaseType> {
21 spec: ObjectCreate,
22 src_objs: Vec<ObjectSource>,
23 ties: Vec<CreateTieSpec>,
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);
58 self
59 }
60
61 pub fn add_tie(mut self, tie: CreateTieSpec) -> Self {
63 self.ties.push(tie);
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
73fn bind_name(id: ObjID, name: &str) -> Result<()> {
74 let create = twizzler_rt_abi::bindings::create_options {
75 id: id.raw(),
76 kind: CREATE_KIND_NEW,
77 };
78 let fd = twizzler_rt_abi::fd::twz_rt_fd_open(name, create, 0)?;
79 twizzler_rt_abi::fd::twz_rt_fd_close(fd);
80 Ok(())
81}
82
83impl<Base: BaseType + StoreCopy> ObjectBuilder<Base> {
84 pub fn build(&self, base: Base) -> Result<Object<Base>> {
97 if !self
98 .spec
99 .def_prot
100 .contains(Protections::READ | Protections::WRITE)
101 {
102 panic!(
104 "Unable to build object! Default permissions must contain READ | WRITE...\n
105 If you would like to build an object without those permissions, look at the
106 `twizzler_security::SecureBuilderExt` trait
107 "
108 )
109 }
110 self.build_inplace(|tx| tx.write(base))
111 }
112}
113
114impl<Base: BaseType> ObjectBuilder<Base> {
115 pub fn build_inplace<F>(&self, ctor: F) -> Result<Object<Base>>
126 where
127 F: FnOnce(TxObject<MaybeUninit<Base>>) -> Result<TxObject<Base>>,
128 {
129 tracing::trace!("object spec{:#?}", self.spec);
130
131 let id = twizzler_abi::syscall::sys_object_create(
132 self.spec,
133 self.src_objs.as_slice(),
134 self.ties.as_slice(),
135 )?;
136 let mut flags = MapFlags::READ | MapFlags::WRITE;
137 if self.spec.lt == LifetimeType::Persistent {
138 flags.insert(MapFlags::PERSIST);
139 if let Some(ref name) = self.name {
140 bind_name(id, name)?;
141 }
142 } else {
143 if let Some(ref name) = self.name {
144 tracing::warn!(
145 "tried to name volatile object at creation time: {} {}",
146 id,
147 name
148 );
149 }
150 }
151
152 tracing::trace!("Creating object with id: {id:?}");
153 let mu_object = unsafe { Object::<MaybeUninit<Base>>::map_unchecked(id, flags) }?;
154 let metadata = mu_object.meta_ptr();
155
156 unsafe {
157 tracing::trace!("metadata:{:#?}", *metadata);
158 }
159
160 let object = ctor(mu_object.into_tx()?)?;
161 object.into_object()
162 }
163
164 pub unsafe fn build_ctor<F>(&self, ctor: F) -> Result<Object<Base>>
186 where
187 F: FnOnce(&mut TxObject<MaybeUninit<Base>>),
188 {
189 self.build_inplace(|mut tx| {
190 ctor(&mut tx);
191 Ok(tx.assume_init())
192 })
193 }
194}
195
196impl<Base: BaseType> Default for ObjectBuilder<Base> {
197 fn default() -> Self {
198 Self::new(ObjectCreate::new(
199 BackingType::Normal,
200 LifetimeType::Volatile,
201 None,
202 ObjectCreateFlags::empty(),
203 Protections::all(),
204 ))
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use super::ObjectBuilder;
211 use crate::{marker::BaseType, object::TypedObject, ptr::InvPtr};
212
213 #[test]
214 fn builder_simple() {
215 let builder = ObjectBuilder::default();
216 let obj = builder.build(42u32).unwrap();
217 let base = obj.base();
218 assert_eq!(*base, 42);
219 }
220
221 struct Foo {
222 ptr: InvPtr<u32>,
223 }
224 impl BaseType for Foo {}
225
226 #[test]
227 fn builder_complex() {
228 let builder = ObjectBuilder::default();
229 let obj_1 = builder.build(42u32).unwrap();
230 let base = obj_1.base_ref();
231 assert_eq!(*base, 42);
232
233 let builder = ObjectBuilder::<Foo>::default();
234 let obj = builder
235 .build_inplace(|tx| {
236 let foo = Foo {
237 ptr: InvPtr::new(&tx, base)?,
238 };
239 tx.write(foo)
240 })
241 .unwrap();
242 let base_foo = obj.base();
243 let r = unsafe { base_foo.ptr.resolve() };
244 assert_eq!(*r, 42);
245 }
246}