Skip to main content

selium_abi/
process.rs

1use rkyv::{Archive, Deserialize, Serialize};
2
3use crate::{
4    AbiParam, AbiScalarType, AbiScalarValue, AbiSignature, CallPlanError, GuestResourceId,
5};
6
7/// Argument supplied to a process entrypoint.
8#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
9#[rkyv(bytecheck())]
10pub enum EntrypointArg {
11    /// Immediate scalar value.
12    Scalar(AbiScalarValue),
13    /// Raw buffer.
14    Buffer(Vec<u8>),
15    /// Handle referring to a Selium resource.
16    Resource(GuestResourceId),
17}
18
19/// Invocation of a process entrypoint.
20#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
21#[rkyv(bytecheck())]
22pub struct EntrypointInvocation {
23    /// ABI signature describing the entrypoint.
24    pub signature: AbiSignature,
25    /// Concrete arguments supplied by the caller.
26    pub args: Vec<EntrypointArg>,
27}
28
29impl EntrypointInvocation {
30    /// Construct an invocation, validating that arguments satisfy the signature.
31    pub fn new(signature: AbiSignature, args: Vec<EntrypointArg>) -> Result<Self, CallPlanError> {
32        let invocation = Self { signature, args };
33        invocation.validate()?;
34        Ok(invocation)
35    }
36
37    /// Validate that arguments align with the ABI signature.
38    pub fn validate(&self) -> Result<(), CallPlanError> {
39        if self.signature.params().len() != self.args.len() {
40            return Err(CallPlanError::ParameterCount {
41                expected: self.signature.params().len(),
42                actual: self.args.len(),
43            });
44        }
45
46        for (index, (param, arg)) in self
47            .signature
48            .params()
49            .iter()
50            .zip(self.args.iter())
51            .enumerate()
52        {
53            match (param, arg) {
54                (AbiParam::Scalar(expected), EntrypointArg::Scalar(actual)) => {
55                    if actual.kind() != *expected {
56                        return Err(CallPlanError::ValueMismatch {
57                            index,
58                            reason: "scalar type mismatch",
59                        });
60                    }
61                }
62                (AbiParam::Scalar(AbiScalarType::I32), EntrypointArg::Resource(_))
63                | (AbiParam::Scalar(AbiScalarType::U64), EntrypointArg::Resource(_)) => {}
64                (AbiParam::Buffer, EntrypointArg::Buffer(_)) => {}
65                _ => {
66                    return Err(CallPlanError::ValueMismatch {
67                        index,
68                        reason: "argument incompatible with signature",
69                    });
70                }
71            }
72        }
73
74        Ok(())
75    }
76
77    /// Access the invocation signature.
78    pub fn signature(&self) -> &AbiSignature {
79        &self.signature
80    }
81}
82
83/// Register a process's logging channel with the host.
84#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
85#[rkyv(bytecheck())]
86pub struct ProcessLogRegistration {
87    /// Shared channel handle exported by the guest.
88    pub channel: GuestResourceId,
89}
90
91/// Request the logging channel for a running process.
92#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
93#[rkyv(bytecheck())]
94pub struct ProcessLogLookup {
95    /// Handle referencing the process to inspect.
96    pub process_id: GuestResourceId,
97}
98
99/// Request to start a new process instance.
100#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
101#[rkyv(bytecheck())]
102pub struct ProcessStart {
103    /// Module identifier that should be activated.
104    pub module_id: String,
105    /// Friendly process name.
106    pub name: String,
107    /// Capabilities granted to the process.
108    pub capabilities: Vec<crate::Capability>,
109    /// Entrypoint invocation details.
110    pub entrypoint: EntrypointInvocation,
111}