5 /// All possible states of an attribute.
7 /// This enum is used to interpret the value returned by
8 /// [`Repository::get_attr`](crate::Repository::get_attr) and
9 /// [`Repository::get_attr_bytes`](crate::Repository::get_attr_bytes).
10 #[derive(Debug, Clone, Copy, Eq)]
11 pub enum AttrValue
<'string
> {
12 /// The attribute is set to true.
14 /// The attribute is unset (set to false).
16 /// The attribute is set to a [valid UTF-8 string](prim@str).
18 /// The attribute is set to a string that might not be [valid UTF-8](prim@str).
20 /// The attribute is not specified.
24 macro_rules
! from_value
{
25 ($value
:expr
=> $string
:expr
) => {
26 match unsafe { raw::git_attr_value($value.map_or(ptr::null(), |v| v.as_ptr().cast())) }
{
27 raw
::GIT_ATTR_VALUE_TRUE
=> Self::True
,
28 raw
::GIT_ATTR_VALUE_FALSE
=> Self::False
,
29 raw
::GIT_ATTR_VALUE_STRING
=> $string
,
30 raw
::GIT_ATTR_VALUE_UNSPECIFIED
=> Self::Unspecified
,
36 impl<'string
> AttrValue
<'string
> {
37 /// Returns the state of an attribute by inspecting its [value](crate::Repository::get_attr)
38 /// by a [string](prim@str).
40 /// This function always returns [`AttrValue::String`] and never returns [`AttrValue::Bytes`]
41 /// when the attribute is set to a string.
42 pub fn from_string(value
: Option
<&'string
str>) -> Self {
43 from_value
!(value
=> Self::String(value
.unwrap()))
46 /// Returns the state of an attribute by inspecting its [value](crate::Repository::get_attr_bytes)
47 /// by a [byte](u8) [slice].
49 /// This function will perform UTF-8 validation when the attribute is set to a string, returns
50 /// [`AttrValue::String`] if it's valid UTF-8 and [`AttrValue::Bytes`] otherwise.
51 pub fn from_bytes(value
: Option
<&'string
[u8]>) -> Self {
52 let mut value
= Self::always_bytes(value
);
53 if let Self::Bytes(bytes
) = value
{
54 if let Ok(string
) = str::from_utf8(bytes
) {
55 value
= Self::String(string
);
61 /// Returns the state of an attribute just like [`AttrValue::from_bytes`], but skips UTF-8
62 /// validation and always returns [`AttrValue::Bytes`] when it's set to a string.
63 pub fn always_bytes(value
: Option
<&'string
[u8]>) -> Self {
64 from_value
!(value
=> Self::Bytes(value
.unwrap()))
68 /// Compare two [`AttrValue`]s.
70 /// Note that this implementation does not differentiate between [`AttrValue::String`] and
71 /// [`AttrValue::Bytes`].
72 impl PartialEq
for AttrValue
<'_
> {
73 fn eq(&self, other
: &AttrValue
<'_
>) -> bool
{
75 (Self::True
, AttrValue
::True
)
76 | (Self::False
, AttrValue
::False
)
77 | (Self::Unspecified
, AttrValue
::Unspecified
) => true,
78 (AttrValue
::String(string
), AttrValue
::Bytes(bytes
))
79 | (AttrValue
::Bytes(bytes
), AttrValue
::String(string
)) => string
.as_bytes() == *bytes
,
80 (AttrValue
::String(left
), AttrValue
::String(right
)) => left
== right
,
81 (AttrValue
::Bytes(left
), AttrValue
::Bytes(right
)) => left
== right
,
91 macro_rules
! test_attr_value
{
92 ($function
:ident
, $variant
:ident
) => {
93 const ATTR_TRUE
: &str = "[internal]__TRUE__";
94 const ATTR_FALSE
: &str = "[internal]__FALSE__";
95 const ATTR_UNSET
: &str = "[internal]__UNSET__";
96 let as_bytes
= AsRef
::<[u8]>::as_ref
;
97 // Use `matches!` here since the `PartialEq` implementation does not differentiate
98 // between `String` and `Bytes`.
100 AttrValue
::$
function(Some(ATTR_TRUE
.as_ref())),
101 AttrValue
::$
variant(s
) if as_bytes(s
) == ATTR_TRUE
.as_bytes()
104 AttrValue
::$
function(Some(ATTR_FALSE
.as_ref())),
105 AttrValue
::$
variant(s
) if as_bytes(s
) == ATTR_FALSE
.as_bytes()
108 AttrValue
::$
function(Some(ATTR_UNSET
.as_ref())),
109 AttrValue
::$
variant(s
) if as_bytes(s
) == ATTR_UNSET
.as_bytes()
112 AttrValue
::$
function(Some("foo".as_ref())),
113 AttrValue
::$
variant(s
) if as_bytes(s
) == b
"foo"
116 AttrValue
::$
function(Some("bar".as_ref())),
117 AttrValue
::$
variant(s
) if as_bytes(s
) == b
"bar"
119 assert_eq
!(AttrValue
::$
function(None
), AttrValue
::Unspecified
);
124 fn attr_value_from_string() {
125 test_attr_value
!(from_string
, String
);
129 fn attr_value_from_bytes() {
130 test_attr_value
!(from_bytes
, String
);
132 AttrValue
::from_bytes(Some(&[0xff])),
133 AttrValue
::Bytes(&[0xff])
136 AttrValue
::from_bytes(Some(b
"\xffoobar")),
137 AttrValue
::Bytes(b
"\xffoobar")
142 fn attr_value_always_bytes() {
143 test_attr_value
!(always_bytes
, Bytes
);
145 AttrValue
::always_bytes(Some(&[0xff; 2])),
146 AttrValue
::Bytes(&[0xff, 0xff])
149 AttrValue
::always_bytes(Some(b
"\xffoo")),
150 AttrValue
::Bytes(b
"\xffoo")
155 fn attr_value_partial_eq() {
156 assert_eq
!(AttrValue
::True
, AttrValue
::True
);
157 assert_eq
!(AttrValue
::False
, AttrValue
::False
);
158 assert_eq
!(AttrValue
::String("foo"), AttrValue
::String("foo"));
159 assert_eq
!(AttrValue
::Bytes(b
"foo"), AttrValue
::Bytes(b
"foo"));
160 assert_eq
!(AttrValue
::String("bar"), AttrValue
::Bytes(b
"bar"));
161 assert_eq
!(AttrValue
::Bytes(b
"bar"), AttrValue
::String("bar"));
162 assert_eq
!(AttrValue
::Unspecified
, AttrValue
::Unspecified
);
163 assert_ne
!(AttrValue
::True
, AttrValue
::False
);
164 assert_ne
!(AttrValue
::False
, AttrValue
::Unspecified
);
165 assert_ne
!(AttrValue
::Unspecified
, AttrValue
::True
);
166 assert_ne
!(AttrValue
::True
, AttrValue
::String("true"));
167 assert_ne
!(AttrValue
::Unspecified
, AttrValue
::Bytes(b
"unspecified"));
168 assert_ne
!(AttrValue
::Bytes(b
"false"), AttrValue
::False
);
169 assert_ne
!(AttrValue
::String("unspecified"), AttrValue
::Unspecified
);
170 assert_ne
!(AttrValue
::String("foo"), AttrValue
::String("bar"));
171 assert_ne
!(AttrValue
::Bytes(b
"foo"), AttrValue
::Bytes(b
"bar"));
172 assert_ne
!(AttrValue
::String("foo"), AttrValue
::Bytes(b
"bar"));
173 assert_ne
!(AttrValue
::Bytes(b
"foo"), AttrValue
::String("bar"));