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 Result,
15};
16
17#[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 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 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 pub fn cast<U: BaseType>(self) -> ObjectBuilder<U> {
51 ObjectBuilder::<U>::new(self.spec)
52 }
53
54 pub fn add_src(mut self, obj_src: ObjectSource) -> Self {
56 self.src_objs.push(obj_src);
57 self
58 }
59
60 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 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 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 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}