Skip to main content

selinux/new_policy/
traits.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::fmt::Debug;
6use std::hash::Hash;
7
8use super::NewPolicy;
9use super::error::{ParseError, SerializeError, ValidateError};
10use super::parser::{PolicyCursor, PolicyWriter};
11
12/// Trait for types that can be parsed from a [`PolicyCursor`].
13pub trait Parse: Sized {
14    fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError>;
15}
16
17/// Trait for types that can be serialized into a byte vector.
18pub trait Serialize {
19    fn serialize(&self, writer: &mut PolicyWriter<'_>) -> Result<(), SerializeError>;
20}
21
22/// Trait for types that can be validated against the parsed policy.
23pub trait Validate {
24    fn validate(&self, policy: &NewPolicy) -> Result<(), ValidateError>;
25}
26
27/// Trait for strongly-typed policy identifiers.
28///
29/// Types implementing [`PolicyId`] can be parsed from and serialized to `u32` values
30/// in the binary policy database, but are represented as strongly-typed integers
31/// (often wrapping `NonZeroU16` or `NonZeroU32`) in the logical domain model.
32pub trait PolicyId: Copy + Clone + Debug + Eq + Hash + PartialEq {
33    /// Returns the raw `u32` value of the ID.
34    fn as_u32(&self) -> u32;
35
36    /// Constructs an instance of [`Self`] from a raw `u32` value, returning [`None`]
37    /// if the value is invalid (e.g. zero for a non-optional ID, or out of range).
38    fn from_u32(value: u32) -> Option<Self>;
39}
40
41// Blanket implementations for all strongly-typed IDs
42impl<T: PolicyId> Parse for T {
43    fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
44        let value = u32::parse(cursor)?;
45        T::from_u32(value).ok_or(ParseError::InvalidId { value })
46    }
47}
48
49impl<T: PolicyId> Serialize for T {
50    fn serialize(&self, writer: &mut PolicyWriter<'_>) -> Result<(), SerializeError> {
51        self.as_u32().serialize(writer)
52    }
53}
54
55impl<T: PolicyId> Parse for Option<T> {
56    fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
57        let value = u32::parse(cursor)?;
58        if value == 0 {
59            Ok(None)
60        } else {
61            T::from_u32(value).map(Some).ok_or(ParseError::InvalidId { value })
62        }
63    }
64}
65
66impl<T: PolicyId> Serialize for Option<T> {
67    fn serialize(&self, writer: &mut PolicyWriter<'_>) -> Result<(), SerializeError> {
68        match self {
69            Some(id) => id.as_u32().serialize(writer),
70            None => 0u32.serialize(writer),
71        }
72    }
73}
74
75/// Trait for policy elements with a byte slice name.
76pub trait HasName {
77    fn name(&self) -> &[u8];
78}
79
80/// Trait for policy elements that have a strongly-typed policy identifier.
81pub trait HasPolicyId {
82    type Id: PolicyId;
83    fn id(&self) -> Self::Id;
84}
85
86impl<T: Validate> Validate for Box<T> {
87    fn validate(&self, policy: &NewPolicy) -> Result<(), ValidateError> {
88        (**self).validate(policy)
89    }
90}
91
92impl Validate for bool {
93    fn validate(&self, _policy: &NewPolicy) -> Result<(), ValidateError> {
94        Ok(())
95    }
96}
97
98impl<T: Validate> Validate for Option<T> {
99    fn validate(&self, policy: &NewPolicy) -> Result<(), ValidateError> {
100        if let Some(value) = self {
101            value.validate(policy)?;
102        }
103        Ok(())
104    }
105}