summaryrefslogtreecommitdiffstats
path: root/vendor/gix-attributes/src/state.rs
blob: 80ebcfead565315d77ac25323120433f8f679c46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use bstr::{BStr, ByteSlice};
use kstring::{KString, KStringRef};

use crate::{State, StateRef};

/// A container to encapsulate a tightly packed and typically unallocated byte value that isn't necessarily UTF8 encoded.
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Value(KString);

/// A reference container to encapsulate a tightly packed and typically unallocated byte value that isn't necessarily UTF8 encoded.
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ValueRef<'a>(#[cfg_attr(feature = "serde", serde(borrow))] KStringRef<'a>);

/// Lifecycle
impl<'a> ValueRef<'a> {
    /// Keep `input` as our value.
    pub fn from_bytes(input: &'a [u8]) -> Self {
        Self(KStringRef::from_ref(
            // SAFETY: our API makes accessing that value as `str` impossible, so illformed UTF8 is never exposed as such.
            #[allow(unsafe_code)]
            unsafe {
                std::str::from_utf8_unchecked(input)
            },
        ))
    }
}

/// Access and conversions
impl ValueRef<'_> {
    /// Access this value as byte string.
    pub fn as_bstr(&self) -> &BStr {
        self.0.as_bytes().as_bstr()
    }

    /// Convert this instance into its owned form.
    pub fn to_owned(self) -> Value {
        self.into()
    }
}

impl<'a> From<&'a str> for ValueRef<'a> {
    fn from(v: &'a str) -> Self {
        ValueRef(v.into())
    }
}

impl<'a> From<ValueRef<'a>> for Value {
    fn from(v: ValueRef<'a>) -> Self {
        Value(v.0.into())
    }
}

impl From<&str> for Value {
    fn from(v: &str) -> Self {
        Value(KString::from_ref(v))
    }
}

/// Access
impl Value {
    /// Return ourselves as reference.
    pub fn as_ref(&self) -> ValueRef<'_> {
        ValueRef(self.0.as_ref())
    }
}

/// Access
impl StateRef<'_> {
    /// Return `true` if the associated attribute was set to be unspecified using the `!attr` prefix or it wasn't mentioned.
    pub fn is_unspecified(&self) -> bool {
        matches!(self, StateRef::Unspecified)
    }

    /// Return `true` if the associated attribute was set with `attr`. Note that this will also be `true` if a value is assigned.
    pub fn is_set(&self) -> bool {
        matches!(self, StateRef::Set | StateRef::Value(_))
    }

    /// Return `true` if the associated attribute was set with `-attr` to specifically remove it.
    pub fn is_unset(&self) -> bool {
        matches!(self, StateRef::Unset)
    }

    /// Attempt to obtain the string value of this state, or return `None` if there is no such value.
    pub fn as_bstr(&self) -> Option<&BStr> {
        match self {
            StateRef::Value(v) => Some(v.as_bstr()),
            _ => None,
        }
    }
}

/// Initialization
impl<'a> StateRef<'a> {
    /// Keep `input` in one of our enums.
    pub fn from_bytes(input: &'a [u8]) -> Self {
        Self::Value(ValueRef::from_bytes(input))
    }
}

/// Access
impl<'a> StateRef<'a> {
    /// Turn ourselves into our owned counterpart.
    pub fn to_owned(self) -> State {
        self.into()
    }
}

impl<'a> State {
    /// Turn ourselves into our ref-type.
    pub fn as_ref(&'a self) -> StateRef<'a> {
        match self {
            State::Value(v) => StateRef::Value(v.as_ref()),
            State::Set => StateRef::Set,
            State::Unset => StateRef::Unset,
            State::Unspecified => StateRef::Unspecified,
        }
    }
}

impl<'a> From<StateRef<'a>> for State {
    fn from(s: StateRef<'a>) -> Self {
        match s {
            StateRef::Value(v) => State::Value(v.into()),
            StateRef::Set => State::Set,
            StateRef::Unset => State::Unset,
            StateRef::Unspecified => State::Unspecified,
        }
    }
}