gix_attributes/
state.rs

1use bstr::{BStr, BString, ByteSlice};
2
3use crate::{State, StateRef};
4
5/// A container to encapsulate a tightly packed and typically unallocated byte value that isn't necessarily UTF8 encoded.
6#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8// TODO: This should be some sort of 'smallbstring' - but can't use `kstring` here due to UTF8 requirement. 5% performance boost possible.
9//       What's really needed here is a representation that displays as string when serialized which helps with JSON.
10//       Maybe `smallvec` with display and serialization wrapper would do the trick?
11pub struct Value(BString);
12
13/// A reference container to encapsulate a tightly packed and typically unallocated byte value that isn't necessarily UTF8 encoded.
14#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct ValueRef<'a>(#[cfg_attr(feature = "serde", serde(borrow))] &'a [u8]);
17
18/// Lifecycle
19impl<'a> ValueRef<'a> {
20    /// Keep `input` as our value.
21    pub fn from_bytes(input: &'a [u8]) -> Self {
22        Self(input)
23    }
24}
25
26/// Access and conversions
27impl<'a> ValueRef<'a> {
28    /// Access this value as byte string.
29    pub fn as_bstr(&self) -> &'a BStr {
30        self.0.as_bytes().as_bstr()
31    }
32
33    /// Convert this instance into its owned form.
34    pub fn to_owned(self) -> Value {
35        self.into()
36    }
37}
38
39impl<'a> From<&'a str> for ValueRef<'a> {
40    fn from(v: &'a str) -> Self {
41        ValueRef(v.as_bytes())
42    }
43}
44
45impl<'a> From<ValueRef<'a>> for Value {
46    fn from(v: ValueRef<'a>) -> Self {
47        Value(v.0.into())
48    }
49}
50
51impl From<&str> for Value {
52    fn from(v: &str) -> Self {
53        Value(v.as_bytes().into())
54    }
55}
56
57/// Access
58impl Value {
59    /// Return ourselves as reference.
60    pub fn as_ref(&self) -> ValueRef<'_> {
61        ValueRef(self.0.as_ref())
62    }
63}
64
65/// Access
66impl StateRef<'_> {
67    /// Return `true` if the associated attribute was set to be unspecified using the `!attr` prefix or it wasn't mentioned.
68    pub fn is_unspecified(&self) -> bool {
69        matches!(self, StateRef::Unspecified)
70    }
71
72    /// Return `true` if the associated attribute was set with `attr`. Note that this will also be `true` if a value is assigned.
73    pub fn is_set(&self) -> bool {
74        matches!(self, StateRef::Set | StateRef::Value(_))
75    }
76
77    /// Return `true` if the associated attribute was set with `-attr` to specifically remove it.
78    pub fn is_unset(&self) -> bool {
79        matches!(self, StateRef::Unset)
80    }
81
82    /// Attempt to obtain the string value of this state, or return `None` if there is no such value.
83    pub fn as_bstr(&self) -> Option<&BStr> {
84        match self {
85            StateRef::Value(v) => Some(v.as_bstr()),
86            _ => None,
87        }
88    }
89}
90
91/// Initialization
92impl<'a> StateRef<'a> {
93    /// Keep `input` in one of our enums.
94    pub fn from_bytes(input: &'a [u8]) -> Self {
95        Self::Value(ValueRef::from_bytes(input))
96    }
97}
98
99/// Access
100impl StateRef<'_> {
101    /// Turn ourselves into our owned counterpart.
102    pub fn to_owned(self) -> State {
103        self.into()
104    }
105}
106
107impl<'a> State {
108    /// Turn ourselves into our ref-type.
109    pub fn as_ref(&'a self) -> StateRef<'a> {
110        match self {
111            State::Value(v) => StateRef::Value(v.as_ref()),
112            State::Set => StateRef::Set,
113            State::Unset => StateRef::Unset,
114            State::Unspecified => StateRef::Unspecified,
115        }
116    }
117}
118
119impl<'a> From<StateRef<'a>> for State {
120    fn from(s: StateRef<'a>) -> Self {
121        match s {
122            StateRef::Value(v) => State::Value(v.into()),
123            StateRef::Set => State::Set,
124            StateRef::Unset => State::Unset,
125            StateRef::Unspecified => State::Unspecified,
126        }
127    }
128}