sim_lib_stream_core/citizen.rs
1//! Object/class citizenship for stream packets in the runtime.
2//!
3//! [`StreamPacketDescriptor`] is the runtime citizen wrapping a
4//! [`StreamPacket`]: it derives `Citizen` under the `stream/Packet` class so a
5//! packet can live as a first-class object, and stores the packet in its
6//! encoded [`Expr`] form while validating that the expr decodes back to a
7//! packet. [`stream_packet_class_symbol`] returns the class symbol that
8//! identifies these citizens.
9
10use sim_citizen_derive::Citizen;
11use sim_kernel::{Expr, Result, Symbol};
12
13use crate::{DataPacket, StreamPacket};
14
15/// Runtime citizen wrapping a [`StreamPacket`] under the `stream/Packet` class.
16///
17/// The packet is held in its encoded [`Expr`] form; construction validates that
18/// the expr round-trips to a [`StreamPacket`].
19#[derive(Clone, Debug, PartialEq, Citizen)]
20#[citizen(symbol = "stream/Packet", version = 1)]
21pub struct StreamPacketDescriptor {
22 #[citizen(with = "packet_expr")]
23 packet: Expr,
24}
25
26impl StreamPacketDescriptor {
27 /// Wraps a [`StreamPacket`], storing its encoded [`Expr`] form.
28 pub fn new(packet: StreamPacket) -> Self {
29 Self {
30 packet: packet.to_expr(),
31 }
32 }
33
34 /// Wraps an already-encoded packet [`Expr`], validating that it decodes to a
35 /// [`StreamPacket`].
36 ///
37 /// Returns an error if the expression is not a valid encoded stream packet.
38 pub fn from_expr(expr: Expr) -> Result<Self> {
39 packet_expr::decode(&expr)?;
40 Ok(Self { packet: expr })
41 }
42
43 /// Decodes and returns the wrapped [`StreamPacket`].
44 ///
45 /// Returns an error if the stored expression no longer decodes to a packet.
46 pub fn packet(&self) -> Result<StreamPacket> {
47 StreamPacket::try_from(self.packet.clone())
48 }
49
50 /// Returns the wrapped packet in its encoded [`Expr`] form.
51 pub fn as_expr(&self) -> &Expr {
52 &self.packet
53 }
54}
55
56impl Default for StreamPacketDescriptor {
57 fn default() -> Self {
58 Self::new(StreamPacket::Data(DataPacket::new(
59 Symbol::qualified("stream/data", "citizen-fixture"),
60 Expr::String("packet".to_owned()),
61 )))
62 }
63}
64
65/// Returns the `stream/Packet` class symbol that identifies stream-packet
66/// citizens.
67pub fn stream_packet_class_symbol() -> Symbol {
68 Symbol::qualified("stream", "Packet")
69}
70
71pub(crate) mod packet_expr {
72 use sim_kernel::{Expr, Result};
73
74 use crate::StreamPacket;
75
76 pub fn encode(expr: &Expr) -> Expr {
77 expr.clone()
78 }
79
80 pub fn decode(expr: &Expr) -> Result<Expr> {
81 StreamPacket::try_from(expr.clone())?;
82 Ok(expr.clone())
83 }
84}