1
1
use crate :: timestamp:: Timestamp ;
2
- use memchr:: memchr;
3
2
use std:: borrow:: Cow ;
4
3
use std:: time:: Duration ;
5
4
5
+ #[ derive( Clone , Eq , PartialEq , Hash , Debug ) ]
6
+ pub struct Argument < ' a > {
7
+ pub name : Option < Cow < ' a , str > > ,
8
+ pub value : Cow < ' a , str > ,
9
+ }
10
+
11
+ impl < ' a > Argument < ' a > {
12
+ pub fn new ( value : & ' a str ) -> Self {
13
+ Self { name : None , value : Cow :: from ( value) }
14
+ }
15
+
16
+ pub fn new_named ( name : & ' a str , value : & ' a str ) -> Self {
17
+ Self { name : Some ( Cow :: from ( name) ) , value : Cow :: from ( value) }
18
+ }
19
+ }
20
+
6
21
#[ derive( Clone , Eq , PartialEq , Hash , Debug ) ]
7
22
pub struct Event < ' a > {
8
23
pub event_kind : Cow < ' a , str > ,
9
24
pub label : Cow < ' a , str > ,
10
- pub additional_data : Vec < Cow < ' a , str > > ,
25
+ pub additional_data : Vec < Argument < ' a > > ,
11
26
pub timestamp : Timestamp ,
12
27
pub thread_id : u32 ,
13
28
}
@@ -38,7 +53,7 @@ impl<'a> Event<'a> {
38
53
}
39
54
}
40
55
41
- pub ( crate ) fn parse_event_id ( event_id : Cow < ' a , str > ) -> ( Cow < ' a , str > , Vec < Cow < ' a , str > > ) {
56
+ pub ( crate ) fn parse_event_id ( event_id : Cow < ' a , str > ) -> ( Cow < ' a , str > , Vec < Argument < ' a > > ) {
42
57
let event_id = match event_id {
43
58
Cow :: Owned ( s) => Cow :: Owned ( s. into_bytes ( ) ) ,
44
59
Cow :: Borrowed ( s) => Cow :: Borrowed ( s. as_bytes ( ) ) ,
@@ -75,52 +90,58 @@ struct Parser<'a> {
75
90
pos : usize ,
76
91
}
77
92
78
- const SEPARATOR_BYTE : u8 = measureme:: event_id:: SEPARATOR_BYTE . as_bytes ( ) [ 0 ] ;
93
+ const ARGUMENT_VALUE_TAG_BYTE : u8 = measureme:: event_id:: ARGUMENT_VALUE_TAG_BYTE . as_bytes ( ) [ 0 ] ;
94
+ const ARGUMENT_NAME_TAG_BYTE : u8 = measureme:: event_id:: ARGUMENT_NAME_TAG_BYTE . as_bytes ( ) [ 0 ] ;
79
95
80
96
impl < ' a > Parser < ' a > {
81
97
fn new ( full_text : Cow < ' a , [ u8 ] > ) -> Parser < ' a > {
82
98
Parser { full_text, pos : 0 }
83
99
}
84
100
85
- fn peek ( & self ) -> u8 {
86
- self . full_text [ self . pos ]
87
- }
88
-
89
101
fn parse_label ( & mut self ) -> Result < Cow < ' a , str > , String > {
90
102
assert ! ( self . pos == 0 ) ;
91
- self . parse_separator_terminated_text ( )
103
+ let text = self . parse_text ( ) ?;
104
+ if text. is_empty ( ) {
105
+ return self . err ( "<label> is empty" ) ;
106
+ } else {
107
+ Ok ( text)
108
+ }
92
109
}
93
110
94
- fn parse_separator_terminated_text ( & mut self ) -> Result < Cow < ' a , str > , String > {
111
+ fn parse_text ( & mut self ) -> Result < Cow < ' a , str > , String > {
95
112
let start = self . pos ;
96
-
97
- let end = memchr ( SEPARATOR_BYTE , & self . full_text [ start..] )
98
- . map ( |pos| pos + start)
99
- . unwrap_or ( self . full_text . len ( ) ) ;
100
-
101
- if start == end {
102
- return self . err ( "Zero-length <text>" ) ;
103
- }
104
-
105
- self . pos = end;
106
-
107
- if self . full_text [ start..end] . iter ( ) . any ( u8:: is_ascii_control) {
108
- return self . err ( "Found ASCII control character in <text>" ) ;
109
- }
110
-
111
- Ok ( self . substring ( start, end) )
113
+ self . pos += self . full_text [ start..]
114
+ . iter ( )
115
+ . take_while ( |c| !u8:: is_ascii_control ( c) )
116
+ . count ( ) ;
117
+ Ok ( self . substring ( start, self . pos ) )
112
118
}
113
119
114
- fn parse_arg ( & mut self ) -> Result < Cow < ' a , str > , String > {
115
- if self . peek ( ) != SEPARATOR_BYTE {
116
- return self . err ( & format ! (
117
- "Expected '\\ x{:x}' char at start of <argument>" ,
118
- SEPARATOR_BYTE
119
- ) ) ;
120
+ fn parse_arg ( & mut self ) -> Result < Argument < ' a > , String > {
121
+ let name = if let Some ( & byte) = self . full_text . get ( self . pos ) {
122
+ if byte == ARGUMENT_NAME_TAG_BYTE {
123
+ self . pos += 1 ;
124
+ Some ( self . parse_text ( ) ?)
125
+ } else {
126
+ None
127
+ }
128
+ } else {
129
+ None
130
+ } ;
131
+ let value = if let Some ( & byte) = self . full_text . get ( self . pos ) {
132
+ if byte == ARGUMENT_VALUE_TAG_BYTE {
133
+ self . pos += 1 ;
134
+ Some ( self . parse_text ( ) ?)
135
+ } else {
136
+ None
137
+ }
138
+ } else {
139
+ None
140
+ } ;
141
+ match ( name, value) {
142
+ ( name, Some ( value) ) => Ok ( Argument { name, value } ) ,
143
+ ( _, None ) => self . err ( "Unable to parse required <argument_value>" ) ,
120
144
}
121
-
122
- self . pos += 1 ;
123
- self . parse_separator_terminated_text ( )
124
145
}
125
146
126
147
fn err < T > ( & self , message : & str ) -> Result < T , String > {
@@ -161,7 +182,7 @@ mod tests {
161
182
let ( label, args) = Event :: parse_event_id ( Cow :: from ( "foo\x1e my_arg" ) ) ;
162
183
163
184
assert_eq ! ( label, "foo" ) ;
164
- assert_eq ! ( args, vec![ Cow :: from ( "my_arg" ) ] ) ;
185
+ assert_eq ! ( args, vec![ Argument :: new ( "my_arg" ) ] ) ;
165
186
}
166
187
167
188
#[ test]
@@ -171,7 +192,21 @@ mod tests {
171
192
assert_eq ! ( label, "foo" ) ;
172
193
assert_eq ! (
173
194
args,
174
- vec![ Cow :: from( "arg1" ) , Cow :: from( "arg2" ) , Cow :: from( "arg3" ) ]
195
+ vec![ Argument :: new( "arg1" ) , Argument :: new( "arg2" ) , Argument :: new( "arg3" ) ]
196
+ ) ;
197
+ }
198
+
199
+ #[ test]
200
+ fn parse_event_id_n_named_args ( ) {
201
+ let ( label, args) = Event :: parse_event_id ( Cow :: from ( "foo\x1d arg1\x1e val1\x1d arg2\x1e val2" ) ) ;
202
+
203
+ assert_eq ! ( label, "foo" ) ;
204
+ assert_eq ! (
205
+ args,
206
+ vec![
207
+ Argument :: new_named( "arg1" , "val1" ) ,
208
+ Argument :: new_named( "arg2" , "val2" ) ,
209
+ ]
175
210
) ;
176
211
}
177
212
}
0 commit comments