gix_attributes/
state.rs

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