1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use std::mem::MaybeUninit;

use twizzler_abi::{
    marker::BaseType,
    object::{ObjID, Protections},
    syscall::{
        sys_object_create, BackingType, CreateTieFlags, CreateTieSpec, LifetimeType, ObjectCreate,
        ObjectCreateError, ObjectCreateFlags, ObjectSource,
    },
};

use crate::{
    init::{ObjectInitError, ObjectInitFlags},
    object::Object,
};

/// A builder-pattern type for making a new object.
pub struct CreateSpec {
    lifetime: LifetimeType,
    backing: BackingType,
    kuid: Option<ObjID>,
    flags: ObjectCreateFlags,
    ties: Vec<CreateTieSpec>,
    srcs: Vec<ObjectSource>,
}

impl CreateSpec {
    /// Construct a basic CreateSpec.
    pub fn new(lifetime: LifetimeType, backing: BackingType) -> Self {
        Self {
            ties: vec![],
            srcs: vec![],
            lifetime,
            backing,
            kuid: None,
            flags: ObjectCreateFlags::empty(),
        }
    }

    /// Set the public key ID for this new object.
    pub fn key(&mut self, kuid: ObjID) -> &mut Self {
        self.kuid = Some(kuid);
        self
    }

    /// Add a tie to another object.
    pub fn tie<T>(&mut self, other: &Object<T>, flags: CreateTieFlags) -> &mut Self {
        self.ties.push(CreateTieSpec::new(other.id(), flags));
        self
    }

    /// Add a source for object creation.
    pub fn src<T>(&mut self, src: ObjectSource) -> &mut Self {
        self.srcs.push(src);
        self
    }
}

/// Possible object creation errors.
#[derive(Copy, Clone, Debug)]
pub enum CreateError {
    Create(ObjectCreateError),
    Init(ObjectInitError),
}

impl<T> Object<T> {
    fn raw_create(spec: &CreateSpec) -> Result<ObjID, ObjectCreateError> {
        let oc = ObjectCreate::new(spec.backing, spec.lifetime, spec.kuid, spec.flags);
        sys_object_create(oc, &spec.srcs, &spec.ties)
    }

    /// Create an object, setting up the initial value for the base in a closure.
    pub fn create_with(
        spec: &CreateSpec,
        f: impl FnOnce(&mut Object<MaybeUninit<T>>),
    ) -> Result<Self, CreateError> {
        let id = Self::raw_create(spec).map_err(CreateError::Create)?;
        let mut obj = Object::<MaybeUninit<T>>::init_id(
            id,
            Protections::READ | Protections::WRITE,
            ObjectInitFlags::empty(),
        )
        .map_err(CreateError::Init)?;

        f(&mut obj);
        // TODO: persistence barrier
        // TODO: delete if we fail to map
        Ok(unsafe { core::mem::transmute(obj) })
    }
}

impl<T: BaseType> Object<T> {
    /// Create an object, setting up the initial value for base using the BaseType's init function.
    pub fn create<A>(spec: &CreateSpec, args: A) -> Result<Self, CreateError> {
        let id = Self::raw_create(spec).map_err(CreateError::Create)?;
        let obj = Self::init_id(
            id,
            Protections::READ | Protections::WRITE,
            ObjectInitFlags::empty(),
        )
        .map_err(CreateError::Init)?;
        let base_raw: *mut T = obj.raw_lea_mut(0);
        unsafe {
            base_raw.write(T::init(args));
        }
        // TODO: persistence barrier
        // TODO: delete if we fail to map
        Ok(obj)
    }
}