Skip to main content

sim_lib_auto_core/
session.rs

1//! Automotive session descriptors shared by diagnostic fabric libraries.
2
3use sim_kernel::{CapabilityName, CapabilitySet, diminish};
4
5use crate::{BrandCaps, VehicleId};
6
7/// Placement selected for one automotive diagnostic session.
8#[derive(Clone, Debug, PartialEq, Eq)]
9pub enum TransportPlacement {
10    /// Synthetic in-process ECU data.
11    Modeled,
12    /// Replayable diagnostic cassette identified by a stable label.
13    Cassette {
14        /// Cassette label selected by the caller.
15        id: String,
16    },
17    /// Host-provided bridge selected by name.
18    LocalBridge {
19        /// Bridge label configured by the host.
20        name: String,
21    },
22}
23
24impl TransportPlacement {
25    /// Builds a modeled placement.
26    pub fn modeled() -> Self {
27        Self::Modeled
28    }
29
30    /// Builds a cassette-backed placement.
31    pub fn cassette(id: impl Into<String>) -> Self {
32        Self::Cassette { id: id.into() }
33    }
34
35    /// Builds a local bridge placement.
36    pub fn local_bridge(name: impl Into<String>) -> Self {
37        Self::LocalBridge { name: name.into() }
38    }
39
40    /// Returns the placement family name.
41    pub fn kind(&self) -> &'static str {
42        match self {
43            Self::Modeled => "modeled",
44            Self::Cassette { .. } => "cassette",
45            Self::LocalBridge { .. } => "local-bridge",
46        }
47    }
48}
49
50/// Session state carried by automotive diagnostic fabrics.
51#[derive(Clone, Debug, PartialEq, Eq)]
52pub struct AutoSession {
53    /// Modeled vehicle identity.
54    pub vehicle: VehicleId,
55    /// Brand or workshop capability profile.
56    pub brand: BrandCaps,
57    /// Placement that answers diagnostic requests.
58    pub transport: TransportPlacement,
59    /// Capabilities granted to this session before caller-side narrowing.
60    pub grants: Vec<CapabilityName>,
61}
62
63impl AutoSession {
64    /// Builds a session with explicit placement and grants.
65    pub fn new(
66        vehicle: VehicleId,
67        brand: BrandCaps,
68        transport: TransportPlacement,
69        grants: Vec<CapabilityName>,
70    ) -> Self {
71        Self {
72            vehicle,
73            brand,
74            transport,
75            grants,
76        }
77    }
78
79    /// Builds a modeled session for a synthetic vehicle.
80    pub fn modeled(vehicle: VehicleId, brand: BrandCaps, grants: Vec<CapabilityName>) -> Self {
81        Self::new(vehicle, brand, TransportPlacement::Modeled, grants)
82    }
83
84    /// Returns a copy of this session with a different placement.
85    pub fn with_transport(mut self, transport: TransportPlacement) -> Self {
86        self.transport = transport;
87        self
88    }
89
90    /// Returns whether the session holds `capability` before caller narrowing.
91    pub fn has_grant(&self, capability: &CapabilityName) -> bool {
92        self.grants.iter().any(|grant| grant == capability)
93    }
94
95    /// Intersects the session grants with caller-allowed capabilities.
96    pub fn diminished_grants(&self, allowed: &[CapabilityName]) -> CapabilitySet {
97        let current = capability_set(self.grants.iter().cloned());
98        let allowed = capability_set(allowed.iter().cloned());
99        diminish(&current, &allowed)
100    }
101}
102
103fn capability_set(capabilities: impl IntoIterator<Item = CapabilityName>) -> CapabilitySet {
104    capabilities
105        .into_iter()
106        .fold(CapabilitySet::new(), CapabilitySet::grant)
107}