]> git.proxmox.com Git - rustc.git/blame - extra/git2/src/attr.rs
New upstream version 1.73.0+dfsg1
[rustc.git] / extra / git2 / src / attr.rs
CommitLineData
0a29b90c
FG
1use crate::raw;
2use std::ptr;
3use std::str;
4
5/// All possible states of an attribute.
6///
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)]
11pub enum AttrValue<'string> {
12 /// The attribute is set to true.
13 True,
14 /// The attribute is unset (set to false).
15 False,
16 /// The attribute is set to a [valid UTF-8 string](prim@str).
17 String(&'string str),
18 /// The attribute is set to a string that might not be [valid UTF-8](prim@str).
19 Bytes(&'string [u8]),
20 /// The attribute is not specified.
21 Unspecified,
22}
23
24macro_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,
31 _ => unreachable!(),
32 }
33 };
34}
35
36impl<'string> AttrValue<'string> {
37 /// Returns the state of an attribute by inspecting its [value](crate::Repository::get_attr)
38 /// by a [string](prim@str).
39 ///
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()))
44 }
45
46 /// Returns the state of an attribute by inspecting its [value](crate::Repository::get_attr_bytes)
47 /// by a [byte](u8) [slice].
48 ///
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);
56 }
57 }
58 value
59 }
60
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()))
65 }
66}
67
68/// Compare two [`AttrValue`]s.
69///
70/// Note that this implementation does not differentiate between [`AttrValue::String`] and
71/// [`AttrValue::Bytes`].
72impl PartialEq for AttrValue<'_> {
73 fn eq(&self, other: &AttrValue<'_>) -> bool {
74 match (self, other) {
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,
82 _ => false,
83 }
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::AttrValue;
90
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`.
99 assert!(matches!(
100 AttrValue::$function(Some(ATTR_TRUE.as_ref())),
101 AttrValue::$variant(s) if as_bytes(s) == ATTR_TRUE.as_bytes()
102 ));
103 assert!(matches!(
104 AttrValue::$function(Some(ATTR_FALSE.as_ref())),
105 AttrValue::$variant(s) if as_bytes(s) == ATTR_FALSE.as_bytes()
106 ));
107 assert!(matches!(
108 AttrValue::$function(Some(ATTR_UNSET.as_ref())),
109 AttrValue::$variant(s) if as_bytes(s) == ATTR_UNSET.as_bytes()
110 ));
111 assert!(matches!(
112 AttrValue::$function(Some("foo".as_ref())),
113 AttrValue::$variant(s) if as_bytes(s) == b"foo"
114 ));
115 assert!(matches!(
116 AttrValue::$function(Some("bar".as_ref())),
117 AttrValue::$variant(s) if as_bytes(s) == b"bar"
118 ));
119 assert_eq!(AttrValue::$function(None), AttrValue::Unspecified);
120 };
121 }
122
123 #[test]
124 fn attr_value_from_string() {
125 test_attr_value!(from_string, String);
126 }
127
128 #[test]
129 fn attr_value_from_bytes() {
130 test_attr_value!(from_bytes, String);
131 assert!(matches!(
132 AttrValue::from_bytes(Some(&[0xff])),
133 AttrValue::Bytes(&[0xff])
134 ));
135 assert!(matches!(
136 AttrValue::from_bytes(Some(b"\xffoobar")),
137 AttrValue::Bytes(b"\xffoobar")
138 ));
139 }
140
141 #[test]
142 fn attr_value_always_bytes() {
143 test_attr_value!(always_bytes, Bytes);
144 assert!(matches!(
145 AttrValue::always_bytes(Some(&[0xff; 2])),
146 AttrValue::Bytes(&[0xff, 0xff])
147 ));
148 assert!(matches!(
149 AttrValue::always_bytes(Some(b"\xffoo")),
150 AttrValue::Bytes(b"\xffoo")
151 ));
152 }
153
154 #[test]
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"));
174 }
175}