@@ -8,32 +8,93 @@ use std::borrow::Cow;
8
8
///
9
9
/// Not all unset `&RawValues` returned by this library are referentially equal to this one.
10
10
/// This exists to provide an unset raw value for whenever a reference to one is necessary.
11
- pub static UNSET : RawValue = RawValue ( Cow :: Borrowed ( "" ) ) ;
11
+ pub static UNSET : RawValue = RawValue {
12
+ value : Cow :: Borrowed ( "" ) ,
13
+ #[ cfg( feature = "track-source" ) ]
14
+ source : None ,
15
+ } ;
12
16
13
17
/// An unparsed property value.
14
18
///
15
19
/// This is conceptually an optional non-empty string with some convenience methods.
16
- #[ derive( Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Debug , Default ) ]
17
- pub struct RawValue ( Cow < ' static , str > ) ;
20
+ /// With the `track-source` feature,
21
+ /// objects of this type can also track the file and line number they originate from.
22
+ #[ derive( Clone , Debug , Default ) ]
23
+ pub struct RawValue {
24
+ value : Cow < ' static , str > ,
25
+ #[ cfg( feature = "track-source" ) ]
26
+ source : Option < ( std:: sync:: Arc < std:: path:: Path > , usize ) > ,
27
+ }
28
+
29
+ // Manual-impl (Partial)Eq, (Partial)Ord, and Hash so that the source isn't considered.
30
+
31
+ impl PartialEq for RawValue {
32
+ fn eq ( & self , other : & Self ) -> bool {
33
+ self . value == other. value
34
+ }
35
+ }
36
+ impl Eq for RawValue { }
37
+ impl PartialOrd for RawValue {
38
+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
39
+ Some ( self . value . cmp ( & other. value ) )
40
+ }
41
+ }
42
+ impl Ord for RawValue {
43
+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
44
+ self . value . cmp ( & other. value )
45
+ }
46
+ }
47
+ impl std:: hash:: Hash for RawValue {
48
+ fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
49
+ state. write ( self . value . as_bytes ( ) ) ;
50
+ state. write_u8 ( 0 ) ;
51
+ }
52
+ }
18
53
19
54
impl RawValue {
20
55
#[ must_use]
21
56
fn detect_unset ( & self ) -> Option < bool > {
22
57
if self . is_unset ( ) {
23
58
Some ( false )
24
- } else if "unset" . eq_ignore_ascii_case ( self . 0 . as_ref ( ) ) {
59
+ } else if "unset" . eq_ignore_ascii_case ( self . value . as_ref ( ) ) {
25
60
Some ( true )
26
61
} else {
27
62
None
28
63
}
29
64
}
30
65
66
+ #[ cfg( feature = "track-source" ) ]
67
+ /// Returns the path to the file and the line number that this value originates from.
68
+ ///
69
+ /// The line number is 1-indexed to match convention;
70
+ /// the first line will have a line number of 1 rather than 0.
71
+ pub fn source ( & self ) -> Option < ( & std:: path:: Path , usize ) > {
72
+ self . source
73
+ . as_ref ( )
74
+ . map ( |( path, line) | ( std:: sync:: Arc :: as_ref ( path) , * line) )
75
+ }
76
+
77
+ #[ cfg( feature = "track-source" ) ]
78
+ /// Sets the path and line number from which this value originated.
79
+ ///
80
+ /// The line number should be 1-indexed to match convention;
81
+ /// the first line should have a line number of 1 rather than 0.
82
+ pub fn set_source ( & mut self , path : impl Into < std:: sync:: Arc < std:: path:: Path > > , line : usize ) {
83
+ self . source = Some ( ( path. into ( ) , line) )
84
+ }
85
+
86
+ #[ cfg( feature = "track-source" ) ]
87
+ /// Clears the path and line number from which this value originated.
88
+ pub fn clear_source ( & mut self ) {
89
+ self . source = None ;
90
+ }
91
+
31
92
/// Returns true if the value is unset.
32
93
///
33
94
/// Does not handle values of "unset".
34
95
/// See [`RawValue::filter_unset`].
35
96
pub fn is_unset ( & self ) -> bool {
36
- self . 0 . is_empty ( )
97
+ self . value . is_empty ( )
37
98
}
38
99
39
100
/// Returns a reference to.an unset `RawValue`
@@ -66,13 +127,13 @@ impl RawValue {
66
127
if let Some ( v) = self . detect_unset ( ) {
67
128
Err ( v)
68
129
} else {
69
- Ok ( self . 0 . as_ref ( ) )
130
+ Ok ( self . value . as_ref ( ) )
70
131
}
71
132
}
72
133
73
134
/// Converts this `RawValue` into an [`Option`].
74
135
pub fn into_option ( & self ) -> Option < & str > {
75
- Some ( self . 0 . as_ref ( ) ) . filter ( |v| !v. is_empty ( ) )
136
+ Some ( self . value . as_ref ( ) ) . filter ( |v| !v. is_empty ( ) )
76
137
}
77
138
78
139
/// Converts this `RawValue` into `&str`.
@@ -82,7 +143,7 @@ impl RawValue {
82
143
if self . is_unset ( ) {
83
144
"unset"
84
145
} else {
85
- self . 0 . as_ref ( )
146
+ self . value . as_ref ( )
86
147
}
87
148
}
88
149
@@ -111,19 +172,27 @@ impl RawValue {
111
172
/// Returns a lowercased version of `self`.
112
173
#[ must_use]
113
174
pub fn to_lowercase ( & self ) -> Self {
114
- Self ( Cow :: Owned ( self . 0 . to_lowercase ( ) ) )
175
+ Self {
176
+ value : Cow :: Owned ( self . value . to_lowercase ( ) ) ,
177
+ #[ cfg( feature = "track-source" ) ]
178
+ source : self . source . clone ( ) ,
179
+ }
115
180
}
116
181
}
117
182
118
183
impl std:: fmt:: Display for RawValue {
119
184
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
120
- write ! ( f, "{}" , self . 0 . as_ref( ) )
185
+ write ! ( f, "{}" , self . value . as_ref( ) )
121
186
}
122
187
}
123
188
124
189
impl From < String > for RawValue {
125
190
fn from ( value : String ) -> Self {
126
- RawValue ( Cow :: Owned ( value) )
191
+ RawValue {
192
+ value : Cow :: Owned ( value) ,
193
+ #[ cfg( feature = "track-source" ) ]
194
+ source : None ,
195
+ }
127
196
}
128
197
}
129
198
@@ -132,7 +201,11 @@ impl From<&'static str> for RawValue {
132
201
if value. is_empty ( ) {
133
202
UNSET . clone ( )
134
203
} else {
135
- RawValue ( Cow :: Borrowed ( value) )
204
+ RawValue {
205
+ value : Cow :: Borrowed ( value) ,
206
+ #[ cfg( feature = "track-source" ) ]
207
+ source : None ,
208
+ }
136
209
}
137
210
}
138
211
}
0 commit comments