1#![deny(rustdoc::broken_intra_doc_links, rustdoc::bare_urls, rust_2018_idioms)]
64#![warn(
65 missing_copy_implementations,
66 missing_debug_implementations,
67 clippy::explicit_iter_loop,
68 clippy::use_self,
69 clippy::clone_on_ref_ptr,
70 clippy::todo,
71 clippy::dbg_macro,
72 unused_crate_dependencies
73)]
74pub mod builder;
77pub use builder::LineProtocolBuilder;
78
79use fmt::Display;
80use log::debug;
81use nom::{
82 branch::alt,
83 bytes::complete::{tag, take_while1},
84 character::complete::digit1,
85 combinator::{map, opt, recognize},
86 multi::many0,
87 sequence::{preceded, separated_pair, terminated, tuple},
88};
89use smallvec::SmallVec;
90use snafu::{ResultExt, Snafu};
91use std::cmp::Ordering;
92use std::{
93 borrow::Cow,
94 char,
95 collections::{btree_map::Entry, BTreeMap},
96 fmt,
97 ops::Deref,
98};
99
100#[derive(Debug, Snafu)]
102#[non_exhaustive]
103pub enum Error {
104 #[snafu(display(r#"Must not contain duplicate tags, but "{}" was repeated"#, tag_key))]
105 DuplicateTag { tag_key: String },
106
107 #[snafu(display(r#"Invalid measurement was provided"#))]
108 MeasurementValueInvalid,
109
110 #[snafu(display(r#"No fields were provided"#))]
111 FieldSetMissing,
112
113 #[snafu(display(r#"Unable to parse integer value '{}'"#, value))]
114 IntegerValueInvalid {
115 source: std::num::ParseIntError,
116 value: String,
117 },
118
119 #[snafu(display(r#"Unable to parse unsigned integer value '{}'"#, value))]
120 UIntegerValueInvalid {
121 source: std::num::ParseIntError,
122 value: String,
123 },
124
125 #[snafu(display(r#"Unable to parse floating-point value '{}'"#, value))]
126 FloatValueInvalid {
127 source: std::num::ParseFloatError,
128 value: String,
129 },
130
131 #[snafu(display(r#"Unable to parse timestamp value '{}'"#, value))]
132 TimestampValueInvalid {
133 source: std::num::ParseIntError,
134 value: String,
135 },
136
137 #[snafu(display(
139 r#"Measurements, tag keys and values, and field keys may not end with a backslash"#
140 ))]
141 EndsWithBackslash,
142
143 #[snafu(display(
144 "Could not parse entire line. Found trailing content: '{}'",
145 trailing_content
146 ))]
147 CannotParseEntireLine { trailing_content: String },
148
149 #[snafu(display(r#"Tag Set Malformed"#))]
150 TagSetMalformed,
151
152 #[snafu(display(r#"A generic parsing error occurred: {:?}"#, kind))]
154 GenericParsingError {
155 kind: nom::error::ErrorKind,
156 trace: Vec<Error>,
157 },
158}
159
160pub type Result<T, E = Error> = std::result::Result<T, E>;
164type IResult<I, T, E = Error> = nom::IResult<I, T, E>;
165
166impl nom::error::ParseError<&str> for Error {
167 fn from_error_kind(_input: &str, kind: nom::error::ErrorKind) -> Self {
168 GenericParsingSnafu {
169 kind,
170 trace: vec![],
171 }
172 .build()
173 }
174
175 fn append(_input: &str, kind: nom::error::ErrorKind, other: Self) -> Self {
176 GenericParsingSnafu {
177 kind,
178 trace: vec![other],
179 }
180 .build()
181 }
182}
183
184#[derive(Debug)]
187pub struct ParsedLine<'a> {
188 pub series: Series<'a>,
189 pub field_set: FieldSet<'a>,
190 pub timestamp: Option<i64>,
191}
192
193impl<'a> ParsedLine<'a> {
194 pub fn column_count(&self) -> usize {
212 1 + self.field_set.len() + self.series.tag_set.as_ref().map_or(0, |t| t.len())
213 }
214
215 pub fn tag_value(&self, tag_key: &str) -> Option<&EscapedStr<'a>> {
217 match &self.series.tag_set {
218 Some(t) => {
219 let t = t.iter().find(|(k, _)| *k == tag_key);
220 t.map(|(_, val)| val)
221 }
222 None => None,
223 }
224 }
225
226 pub fn field_value(&self, field_key: &str) -> Option<&FieldValue<'a>> {
228 let f = self.field_set.iter().find(|(f, _)| *f == field_key);
229 f.map(|(_, val)| val)
230 }
231}
232
233impl<'a> Display for ParsedLine<'a> {
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 write!(f, "{}", self.series)?;
244
245 if !self.field_set.is_empty() {
246 write!(f, " ")?;
247
248 let mut first = true;
249 for (field_name, field_value) in &self.field_set {
250 if !first {
251 write!(f, ",")?;
252 }
253 first = false;
254 escape_and_write_value(f, field_name.as_str(), FIELD_KEY_DELIMITERS)?;
255 write!(f, "={field_value}")?;
256 }
257 }
258
259 if let Some(timestamp) = self.timestamp {
260 write!(f, " {timestamp}")?
261 }
262 Ok(())
263 }
264}
265
266#[derive(Debug)]
269pub struct Series<'a> {
270 raw_input: &'a str,
271 pub measurement: Measurement<'a>,
272 pub tag_set: Option<TagSet<'a>>,
273}
274
275impl<'a> Display for Series<'a> {
277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 escape_and_write_value(f, self.measurement.as_str(), MEASUREMENT_DELIMITERS)?;
279 if let Some(tag_set) = &self.tag_set {
280 write!(f, ",")?;
281 let mut first = true;
282 for (tag_name, tag_value) in tag_set {
283 if !first {
284 write!(f, ",")?;
285 }
286 first = false;
287 escape_and_write_value(f, tag_name.as_str(), TAG_KEY_DELIMITERS)?;
288 write!(f, "=")?;
289 escape_and_write_value(f, tag_value.as_str(), TAG_VALUE_DELIMITERS)?;
290 }
291 }
292 Ok(())
293 }
294}
295
296impl<'a> Series<'a> {
297 pub fn generate_base(self) -> Result<Cow<'a, str>> {
298 match (!self.is_escaped(), self.is_sorted_and_unique()) {
299 (true, true) => Ok(self.raw_input.into()),
300 (_, true) => Ok(self.generate_base_with_escaping().into()),
301 (_, _) => self
302 .generate_base_with_escaping_sorting_deduplicating()
303 .map(Into::into),
304 }
305 }
306
307 fn generate_base_with_escaping(self) -> String {
308 let mut series_base = self.measurement.to_string();
309 for (tag_key, tag_value) in self.tag_set.unwrap_or_default() {
310 use std::fmt::Write;
311 write!(&mut series_base, ",{tag_key}={tag_value}").expect("Could not append string");
312 }
313 series_base
314 }
315
316 fn generate_base_with_escaping_sorting_deduplicating(self) -> Result<String> {
317 let mut unique_sorted_tag_set = BTreeMap::new();
318 for (tag_key, tag_value) in self.tag_set.unwrap_or_default() {
319 match unique_sorted_tag_set.entry(tag_key) {
320 Entry::Vacant(e) => {
321 e.insert(tag_value);
322 }
323 Entry::Occupied(e) => {
324 let (tag_key, _) = e.remove_entry();
325 return DuplicateTagSnafu {
326 tag_key: tag_key.to_string(),
327 }
328 .fail();
329 }
330 }
331 }
332
333 let mut series_base = self.measurement.to_string();
334 for (tag_key, tag_value) in unique_sorted_tag_set {
335 use std::fmt::Write;
336 write!(&mut series_base, ",{tag_key}={tag_value}").expect("Could not append string");
337 }
338
339 Ok(series_base)
340 }
341
342 fn is_escaped(&self) -> bool {
343 self.measurement.is_escaped() || {
344 match &self.tag_set {
345 None => false,
346 Some(tag_set) => tag_set
347 .iter()
348 .any(|(tag_key, tag_value)| tag_key.is_escaped() || tag_value.is_escaped()),
349 }
350 }
351 }
352
353 fn is_sorted_and_unique(&self) -> bool {
354 match &self.tag_set {
355 None => true,
356 Some(tag_set) => {
357 let mut i = tag_set.iter().zip(tag_set.iter().skip(1));
358 i.all(|((last_tag_key, _), (this_tag_key, _))| last_tag_key < this_tag_key)
359 }
360 }
361 }
362}
363
364pub type Measurement<'a> = EscapedStr<'a>;
365
366pub type FieldSet<'a> = SmallVec<[(EscapedStr<'a>, FieldValue<'a>); 4]>;
370
371pub type TagSet<'a> = SmallVec<[(EscapedStr<'a>, EscapedStr<'a>); 8]>;
375
376#[derive(Debug, Clone, PartialEq)]
381pub enum FieldValue<'a> {
382 I64(i64),
383 U64(u64),
384 F64(f64),
385 String(EscapedStr<'a>),
386 Boolean(bool),
387}
388
389impl<'a> FieldValue<'a> {
390 pub fn is_same_type(&self, other: &Self) -> bool {
392 std::mem::discriminant(self) == std::mem::discriminant(other)
393 }
394}
395
396impl<'a> Display for FieldValue<'a> {
401 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402 match self {
403 Self::I64(v) => write!(f, "{v}i"),
404 Self::U64(v) => write!(f, "{v}u"),
405 Self::F64(v) => write!(f, "{v}"),
406 Self::String(v) => escape_and_write_value(f, v, FIELD_VALUE_STRING_DELIMITERS),
407 Self::Boolean(v) => write!(f, "{v}"),
408 }
409 }
410}
411
412#[derive(Debug, Clone, Eq, Hash)]
425pub enum EscapedStr<'a> {
426 SingleSlice(&'a str),
427 CopiedValue(String),
428}
429
430impl fmt::Display for EscapedStr<'_> {
431 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
432 match self {
433 EscapedStr::SingleSlice(s) => s.fmt(f)?,
434 EscapedStr::CopiedValue(s) => s.fmt(f)?,
435 }
436 Ok(())
437 }
438}
439
440impl<'a> EscapedStr<'a> {
441 fn from_slices(v: &[&'a str]) -> EscapedStr<'a> {
442 match v.len() {
443 0 => EscapedStr::SingleSlice(""),
444 1 => EscapedStr::SingleSlice(v[0]),
445 _ => EscapedStr::CopiedValue(v.join("")),
446 }
447 }
448
449 fn is_escaped(&self) -> bool {
450 match self {
451 EscapedStr::SingleSlice(_) => false,
452 EscapedStr::CopiedValue(_) => true,
453 }
454 }
455
456 pub fn as_str(&self) -> &str {
460 self
461 }
462}
463
464impl<'a> Deref for EscapedStr<'a> {
465 type Target = str;
466
467 fn deref(&self) -> &Self::Target {
468 match &self {
469 EscapedStr::SingleSlice(s) => s,
470 EscapedStr::CopiedValue(s) => s,
471 }
472 }
473}
474
475impl<'a> PartialEq for EscapedStr<'a> {
476 fn eq(&self, other: &Self) -> bool {
477 self.as_str() == other.as_str()
478 }
479}
480
481impl<'a> PartialOrd for EscapedStr<'a> {
482 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
483 Some(self.cmp(other))
484 }
485}
486
487impl<'a> Ord for EscapedStr<'a> {
488 fn cmp(&self, other: &Self) -> Ordering {
489 self.as_str().cmp(other.as_str())
490 }
491}
492
493impl<'a> From<&'a str> for EscapedStr<'a> {
494 fn from(other: &'a str) -> Self {
495 EscapedStr::SingleSlice(other)
496 }
497}
498
499impl From<EscapedStr<'_>> for String {
500 fn from(other: EscapedStr<'_>) -> Self {
501 match other {
502 EscapedStr::SingleSlice(s) => s.into(),
503 EscapedStr::CopiedValue(s) => s,
504 }
505 }
506}
507
508impl From<&EscapedStr<'_>> for String {
509 fn from(other: &EscapedStr<'_>) -> Self {
510 other.to_string()
511 }
512}
513
514impl PartialEq<&str> for EscapedStr<'_> {
515 fn eq(&self, other: &&str) -> bool {
516 self.as_str() == *other
517 }
518}
519
520impl PartialEq<String> for EscapedStr<'_> {
521 fn eq(&self, other: &String) -> bool {
522 self.as_str() == other
523 }
524}
525
526pub fn parse_lines(input: &str) -> impl Iterator<Item = Result<ParsedLine<'_>>> {
530 split_lines(input).filter_map(|line| {
531 let i = trim_leading(line);
532
533 if i.is_empty() {
534 return None;
535 }
536
537 let res = match parse_line(i) {
538 Ok((remaining, line)) => {
539 if !remaining.is_empty() {
544 Some(Err(Error::CannotParseEntireLine {
545 trailing_content: String::from(remaining),
546 }))
547 } else {
548 Some(Ok(line))
549 }
550 }
551 Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Some(Err(e)),
552 Err(nom::Err::Incomplete(_)) => unreachable!("Cannot have incomplete data"), };
554
555 if let Some(Err(r)) = &res {
556 debug!("Error parsing line: '{}'. Error was {:?}", line, r);
557 }
558 res
559 })
560}
561
562pub fn split_lines(input: &str) -> impl Iterator<Item = &str> {
573 let mut quoted = false;
575 let mut fields = false;
576
577 let mut equals = 0;
580 let mut commas = 0;
581
582 let mut in_escape = false;
583 input.split(move |c| {
584 if in_escape {
586 in_escape = false;
587 return false;
588 }
589
590 if c == '\\' {
591 in_escape = true;
592 return false;
593 }
594
595 if c == ' ' {
596 fields = true;
597 return false;
598 }
599
600 if fields {
602 if !quoted && c == '=' {
603 equals += 1;
604 return false;
605 } else if !quoted && c == ',' {
606 commas += 1;
607 return false;
608 } else if c == '"' && equals > commas {
609 quoted = !quoted;
610 return false;
611 }
612 }
613
614 if c == '\n' && !quoted {
615 quoted = false;
617 fields = false;
618 equals = 0;
619 commas = 0;
620 assert!(!in_escape);
621 in_escape = false;
622 return true;
623 }
624
625 false
626 })
627}
628
629fn parse_line(i: &str) -> IResult<&str, ParsedLine<'_>> {
630 let field_set = preceded(whitespace, field_set);
631 let timestamp = preceded(whitespace, terminated(timestamp, opt(whitespace)));
632
633 let line = tuple((series, field_set, opt(timestamp)));
634
635 map(line, |(series, field_set, timestamp)| ParsedLine {
636 series,
637 field_set,
638 timestamp,
639 })(i)
640}
641
642fn series(i: &str) -> IResult<&str, Series<'_>> {
643 let series = tuple((measurement, maybe_tagset));
644 let series_and_raw_input = parse_and_recognize(series);
645
646 map(
647 series_and_raw_input,
648 |(raw_input, (measurement, tag_set))| Series {
649 raw_input,
650 measurement,
651 tag_set,
652 },
653 )(i)
654}
655
656fn maybe_tagset(i: &str) -> IResult<&str, Option<TagSet<'_>>, Error> {
659 match tag::<&str, &str, Error>(",")(i) {
660 Err(nom::Err::Error(_)) => Ok((i, None)),
661 Ok((remainder, _)) => {
662 match tag_set(remainder) {
663 Ok((i, ts)) => {
664 if ts.is_empty() {
666 return Err(nom::Err::Error(Error::TagSetMalformed));
667 }
668 Ok((i, Some(ts)))
669 }
670 Err(nom::Err::Error(_)) => TagSetMalformedSnafu.fail().map_err(nom::Err::Error),
671 Err(e) => Err(e),
672 }
673 }
674 Err(e) => Err(e),
675 }
676}
677
678fn measurement(i: &str) -> IResult<&str, Measurement<'_>, Error> {
679 let normal_char = take_while1(|c| {
680 !is_whitespace_boundary_char(c) && !is_null_char(c) && c != ',' && c != '\\'
681 });
682
683 let space = map(tag(" "), |_| " ");
684 let comma = map(tag(","), |_| ",");
685 let backslash = map(tag("\\"), |_| "\\");
686
687 let escaped = alt((comma, space, backslash));
688
689 match escape_or_fallback(normal_char, "\\", escaped)(i) {
690 Err(nom::Err::Error(_)) => MeasurementValueInvalidSnafu.fail().map_err(nom::Err::Error),
691 other => other,
692 }
693}
694
695fn tag_set(i: &str) -> IResult<&str, TagSet<'_>> {
696 let one_tag = separated_pair(tag_key, tag("="), tag_value);
697 parameterized_separated_list(tag(","), one_tag, SmallVec::new, |v, i| v.push(i))(i)
698}
699
700fn tag_key(i: &str) -> IResult<&str, EscapedStr<'_>> {
701 let normal_char = take_while1(|c| !is_whitespace_boundary_char(c) && c != '=' && c != '\\');
702
703 escaped_value(normal_char)(i)
704}
705
706fn tag_value(i: &str) -> IResult<&str, EscapedStr<'_>> {
707 let normal_char = take_while1(|c| !is_whitespace_boundary_char(c) && c != ',' && c != '\\');
708 escaped_value(normal_char)(i)
709}
710
711fn field_set(i: &str) -> IResult<&str, FieldSet<'_>> {
712 let one_field = separated_pair(field_key, tag("="), field_value);
713 let sep = tag(",");
714
715 match parameterized_separated_list1(sep, one_field, SmallVec::new, |v, i| v.push(i))(i) {
716 Err(nom::Err::Error(_)) => FieldSetMissingSnafu.fail().map_err(nom::Err::Error),
717 other => other,
718 }
719}
720
721fn field_key(i: &str) -> IResult<&str, EscapedStr<'_>> {
722 let normal_char = take_while1(|c| !is_whitespace_boundary_char(c) && c != '=' && c != '\\');
723 escaped_value(normal_char)(i)
724}
725
726fn field_value(i: &str) -> IResult<&str, FieldValue<'_>> {
727 let int = map(field_integer_value, FieldValue::I64);
728 let uint = map(field_uinteger_value, FieldValue::U64);
729 let float = map(field_float_value, FieldValue::F64);
730 let string = map(field_string_value, FieldValue::String);
731 let boolv = map(field_bool_value, FieldValue::Boolean);
732
733 alt((int, uint, float, string, boolv))(i)
734}
735
736fn field_integer_value(i: &str) -> IResult<&str, i64> {
737 let tagged_value = terminated(integral_value_signed, tag("i"));
738 map_fail(tagged_value, |value| {
739 value.parse().context(IntegerValueInvalidSnafu { value })
740 })(i)
741}
742
743fn field_uinteger_value(i: &str) -> IResult<&str, u64> {
744 let tagged_value = terminated(digit1, tag("u"));
745 map_fail(tagged_value, |value| {
746 value.parse().context(UIntegerValueInvalidSnafu { value })
747 })(i)
748}
749
750fn field_float_value(i: &str) -> IResult<&str, f64> {
751 let value = alt((
752 field_float_value_with_exponential_and_decimal,
753 field_float_value_with_exponential_no_decimal,
754 field_float_value_with_decimal,
755 field_float_value_no_decimal,
756 ));
757 map_fail(value, |value| {
758 value.parse().context(FloatValueInvalidSnafu { value })
759 })(i)
760}
761
762fn field_float_value_with_decimal(i: &str) -> IResult<&str, &str> {
763 recognize(separated_pair(integral_value_signed, tag("."), digit1))(i)
764}
765
766fn field_float_value_with_exponential_and_decimal(i: &str) -> IResult<&str, &str> {
767 recognize(separated_pair(
768 integral_value_signed,
769 tag("."),
770 exponential_value,
771 ))(i)
772}
773
774fn field_float_value_with_exponential_no_decimal(i: &str) -> IResult<&str, &str> {
775 recognize(preceded(opt(tag("-")), exponential_value))(i)
776}
777
778fn exponential_value(i: &str) -> IResult<&str, &str> {
779 recognize(separated_pair(
780 digit1,
781 tuple((alt((tag("e"), tag("E"))), opt(alt((tag("-"), tag("+")))))),
782 digit1,
783 ))(i)
784}
785
786fn field_float_value_no_decimal(i: &str) -> IResult<&str, &str> {
787 integral_value_signed(i)
788}
789
790fn integral_value_signed(i: &str) -> IResult<&str, &str> {
791 recognize(preceded(opt(tag("-")), digit1))(i)
792}
793
794fn timestamp(i: &str) -> IResult<&str, i64> {
795 map_fail(integral_value_signed, |value| {
796 value.parse().context(TimestampValueInvalidSnafu { value })
797 })(i)
798}
799
800fn field_string_value(i: &str) -> IResult<&str, EscapedStr<'_>> {
801 let string_data = alt((
805 map(tag(r#"\""#), |_| r#"""#), map(tag(r"\\"), |_| r"\"), tag(r"\"), take_while1(|c| c != '\\' && c != '"'), ));
810
811 let empty_str = map(tag(r#""""#), |_| Vec::new());
814
815 let quoted_str = alt((
816 preceded(tag("\""), terminated(many0(string_data), tag("\""))),
817 empty_str,
818 ));
819
820 map(quoted_str, |vec| EscapedStr::from_slices(&vec))(i)
821}
822
823fn field_bool_value(i: &str) -> IResult<&str, bool> {
824 alt((
828 map(tag("true"), |_| true),
829 map(tag("True"), |_| true),
830 map(tag("TRUE"), |_| true),
831 map(tag("t"), |_| true),
832 map(tag("T"), |_| true),
833 map(tag("false"), |_| false),
834 map(tag("False"), |_| false),
835 map(tag("FALSE"), |_| false),
836 map(tag("f"), |_| false),
837 map(tag("F"), |_| false),
838 ))(i)
839}
840
841fn trim_leading(mut i: &str) -> &str {
844 loop {
845 let offset = i
846 .find(|c| !is_whitespace_boundary_char(c))
847 .unwrap_or(i.len());
848 i = &i[offset..];
849
850 if i.starts_with('#') {
851 let offset = i.find('\n').unwrap_or(i.len());
852 i = &i[offset..];
853 } else {
854 break i;
855 }
856 }
857}
858
859fn whitespace(i: &str) -> IResult<&str, &str> {
860 take_while1(|c| c == ' ')(i)
861}
862
863fn is_whitespace_boundary_char(c: char) -> bool {
864 c == ' ' || c == '\t' || c == '\n'
865}
866
867fn is_null_char(c: char) -> bool {
868 c == '\0'
869}
870
871fn escaped_value<'a>(
875 normal: impl Fn(&'a str) -> IResult<&'a str, &'a str>,
876) -> impl FnOnce(&'a str) -> IResult<&'a str, EscapedStr<'a>> {
877 move |i| {
878 let backslash = map(tag("\\"), |_| "\\");
879 let comma = map(tag(","), |_| ",");
880 let equal = map(tag("="), |_| "=");
881 let space = map(tag(" "), |_| " ");
882
883 let escaped = alt((backslash, comma, equal, space));
884
885 escape_or_fallback(normal, "\\", escaped)(i)
886 }
887}
888
889fn escape_or_fallback<'a>(
893 normal: impl FnMut(&'a str) -> IResult<&'a str, &'a str>,
894 escape_char: &'static str,
895 escaped: impl FnMut(&'a str) -> IResult<&'a str, &'a str>,
896) -> impl FnOnce(&'a str) -> IResult<&'a str, EscapedStr<'a>> {
897 move |i| {
898 let (remaining, s) = escape_or_fallback_inner(normal, escape_char, escaped)(i)?;
899
900 if s.ends_with('\\') {
901 EndsWithBackslashSnafu.fail().map_err(nom::Err::Failure)
902 } else {
903 Ok((remaining, s))
904 }
905 }
906}
907
908fn escape_or_fallback_inner<'a, Error>(
909 mut normal: impl FnMut(&'a str) -> IResult<&'a str, &'a str, Error>,
910 escape_char: &'static str,
911 mut escaped: impl FnMut(&'a str) -> IResult<&'a str, &'a str, Error>,
912) -> impl FnMut(&'a str) -> IResult<&'a str, EscapedStr<'a>, Error>
913where
914 Error: nom::error::ParseError<&'a str>,
915{
916 move |i| {
917 let mut result = SmallVec::<[&str; 4]>::new();
918 let mut head = i;
919
920 loop {
921 match normal(head) {
922 Ok((remaining, parsed)) => {
923 result.push(parsed);
924 head = remaining;
925 }
926 Err(nom::Err::Error(_)) => {
927 if head.starts_with(escape_char) {
929 let after = &head[escape_char.len()..];
930
931 match escaped(after) {
932 Ok((remaining, parsed)) => {
933 result.push(parsed);
934 head = remaining;
935 }
936 Err(nom::Err::Error(_)) => {
937 result.push(escape_char);
938 head = after;
939
940 match head.chars().next() {
943 Some(c) => {
944 let (escaped, remaining) = head.split_at(c.len_utf8());
945 result.push(escaped);
946 head = remaining;
947 }
948 None => return Ok((head, EscapedStr::from_slices(&result))),
949 }
950 }
951 Err(e) => return Err(e),
952 }
953 } else {
954 if head == i {
956 return Err(nom::Err::Error(Error::from_error_kind(
957 head,
958 nom::error::ErrorKind::EscapedTransform,
959 )));
960 } else {
961 return Ok((head, EscapedStr::from_slices(&result)));
962 }
963 }
964 }
965 Err(e) => return Err(e),
966 }
967 }
968 }
969}
970
971fn parameterized_separated_list<I, O, O2, E, F, G, Ret>(
974 mut sep: G,
975 mut f: F,
976 cre: impl FnOnce() -> Ret,
977 mut add: impl FnMut(&mut Ret, O),
978) -> impl FnOnce(I) -> IResult<I, Ret, E>
979where
980 I: Clone + PartialEq,
981 F: FnMut(I) -> IResult<I, O, E>,
982 G: FnMut(I) -> IResult<I, O2, E>,
983 E: nom::error::ParseError<I>,
984{
985 move |mut i: I| {
986 let mut res = cre();
987
988 match f(i.clone()) {
989 Err(nom::Err::Error(_)) => return Ok((i, res)),
990 Err(e) => return Err(e),
991 Ok((i1, o)) => {
992 if i1 == i {
993 return Err(nom::Err::Error(E::from_error_kind(
994 i1,
995 nom::error::ErrorKind::SeparatedList,
996 )));
997 }
998
999 add(&mut res, o);
1000 i = i1;
1001 }
1002 }
1003
1004 loop {
1005 match sep(i.clone()) {
1006 Err(nom::Err::Error(_)) => return Ok((i, res)),
1007 Err(e) => return Err(e),
1008 Ok((i1, _)) => {
1009 if i1 == i {
1010 return Err(nom::Err::Error(E::from_error_kind(
1011 i1,
1012 nom::error::ErrorKind::SeparatedList,
1013 )));
1014 }
1015
1016 match f(i1.clone()) {
1017 Err(nom::Err::Error(_)) => return Ok((i, res)),
1018 Err(e) => return Err(e),
1019 Ok((i2, o)) => {
1020 if i2 == i {
1021 return Err(nom::Err::Error(E::from_error_kind(
1022 i2,
1023 nom::error::ErrorKind::SeparatedList,
1024 )));
1025 }
1026
1027 add(&mut res, o);
1028 i = i2;
1029 }
1030 }
1031 }
1032 }
1033 }
1034 }
1035}
1036
1037fn parameterized_separated_list1<I, O, O2, E, F, G, Ret>(
1038 mut sep: G,
1039 mut f: F,
1040 cre: impl FnOnce() -> Ret,
1041 mut add: impl FnMut(&mut Ret, O),
1042) -> impl FnOnce(I) -> IResult<I, Ret, E>
1043where
1044 I: Clone + PartialEq,
1045 F: FnMut(I) -> IResult<I, O, E>,
1046 G: FnMut(I) -> IResult<I, O2, E>,
1047 E: nom::error::ParseError<I>,
1048{
1049 move |i| {
1050 let (rem, first) = f(i)?;
1051
1052 let mut res = cre();
1053 add(&mut res, first);
1054
1055 match sep(rem.clone()) {
1056 Ok((rem, _)) => parameterized_separated_list(sep, f, move || res, add)(rem),
1057 Err(nom::Err::Error(_)) => Ok((rem, res)),
1058 Err(e) => Err(e),
1059 }
1060 }
1061}
1062
1063fn parse_and_recognize<
1066 I: Clone + nom::Offset + nom::Slice<std::ops::RangeTo<usize>>,
1067 O,
1068 E: nom::error::ParseError<I>,
1069 F,
1070>(
1071 mut parser: F,
1072) -> impl FnMut(I) -> IResult<I, (I, O), E>
1073where
1074 F: FnMut(I) -> IResult<I, O, E>,
1075{
1076 move |input: I| {
1077 let i = input.clone();
1078 match parser(i) {
1079 Ok((i, o)) => {
1080 let index = input.offset(&i);
1081 Ok((i, (input.slice(..index), o)))
1082 }
1083 Err(e) => Err(e),
1084 }
1085 }
1086}
1087
1088fn map_fail<'a, R1, R2>(
1091 mut first: impl FnMut(&'a str) -> IResult<&'a str, R1>,
1092 second: impl FnOnce(R1) -> Result<R2, Error>,
1093) -> impl FnOnce(&'a str) -> IResult<&'a str, R2> {
1094 move |i| {
1095 let (remaining, value) = first(i)?;
1096
1097 match second(value) {
1098 Ok(v) => Ok((remaining, v)),
1099 Err(e) => Err(nom::Err::Failure(e)),
1100 }
1101 }
1102}
1103
1104const MEASUREMENT_DELIMITERS: &[char] = &[',', ' '];
1108
1109const TAG_KEY_DELIMITERS: &[char] = &[',', '=', ' '];
1111
1112const TAG_VALUE_DELIMITERS: &[char] = TAG_KEY_DELIMITERS;
1114
1115const FIELD_KEY_DELIMITERS: &[char] = TAG_KEY_DELIMITERS;
1117
1118const FIELD_VALUE_STRING_DELIMITERS: &[char] = &['"']; fn escape_and_write_value(
1126 f: &mut fmt::Formatter<'_>,
1127 value: &str,
1128 escaping_specification: &[char],
1129) -> fmt::Result {
1130 let mut last = 0;
1131
1132 for (idx, delim) in value.match_indices(escaping_specification) {
1133 let s = &value[last..idx];
1134 write!(f, r#"{s}\{delim}"#)?;
1135 last = idx + delim.len();
1136 }
1137
1138 f.write_str(&value[last..])
1139}
1140
1141#[cfg(test)]
1142mod test {
1143 use super::*;
1144 use smallvec::smallvec;
1145 use test_helpers::approximately_equal;
1146
1147 impl FieldValue<'_> {
1148 fn unwrap_i64(&self) -> i64 {
1149 match self {
1150 Self::I64(v) => *v,
1151 _ => panic!("field was not an i64"),
1152 }
1153 }
1154
1155 fn unwrap_u64(&self) -> u64 {
1156 match self {
1157 Self::U64(v) => *v,
1158 _ => panic!("field was not an u64"),
1159 }
1160 }
1161
1162 fn unwrap_f64(&self) -> f64 {
1163 match self {
1164 Self::F64(v) => *v,
1165 _ => panic!("field was not an f64"),
1166 }
1167 }
1168
1169 fn unwrap_string(&self) -> String {
1170 match self {
1171 Self::String(v) => v.to_string(),
1172 _ => panic!("field was not a String"),
1173 }
1174 }
1175
1176 fn unwrap_bool(&self) -> bool {
1177 match self {
1178 Self::Boolean(v) => *v,
1179 _ => panic!("field was not a Bool"),
1180 }
1181 }
1182 }
1183
1184 #[test]
1185 fn parse_lines_returns_all_lines_even_when_a_line_errors() {
1186 let input = ",tag1=1,tag2=2 value=1 123\nm,tag1=one,tag2=2 value=1 123";
1187 let vals = super::parse_lines(input).collect::<Vec<Result<_>>>();
1188 assert!(matches!(
1189 &vals[..],
1190 &[Err(Error::MeasurementValueInvalid), Ok(_)]
1191 ));
1192 }
1193
1194 #[test]
1195 fn escaped_str_basic() {
1196 let es = EscapedStr::from("Foo");
1198 assert_eq!(es, "Foo");
1199 assert!(!es.is_escaped(), "There are no escaped values");
1200 assert!(!es.ends_with('F'));
1201 assert!(!es.ends_with('z'));
1202 assert!(!es.ends_with("zz"));
1203 assert!(es.ends_with('o'));
1204 assert!(es.ends_with("oo"));
1205 assert!(es.ends_with("Foo"));
1206 }
1207
1208 #[test]
1209 fn escaped_str_multi() {
1210 let (remaining, es) = measurement("Foo\\aBar").unwrap();
1213 assert!(remaining.is_empty());
1214 assert_eq!(es, EscapedStr::from_slices(&["Foo", "\\", "a", "Bar"]));
1215 assert!(es.is_escaped());
1216
1217 assert!(es.ends_with("Bar"));
1219
1220 assert!(es == "Foo\\aBar");
1222 assert!(es != "Foo\\aBa");
1223 assert!(es != "Foo\\aBaz");
1224 assert!(es != "Foo\\a");
1225 assert!(es != "Foo\\");
1226 assert!(es != "Foo");
1227 assert!(es != "Fo");
1228 assert!(es != "F");
1229 assert!(es != "");
1230 }
1231
1232 #[test]
1233 fn test_trim_leading() {
1234 assert_eq!(trim_leading(""), "");
1235 assert_eq!(trim_leading(" a b c "), "a b c ");
1236 assert_eq!(trim_leading(" a "), "a ");
1237 assert_eq!(trim_leading("\n a "), "a ");
1238 assert_eq!(trim_leading("\t a "), "a ");
1239
1240 assert_eq!(trim_leading(" #comment\n a "), "a ");
1242 assert_eq!(trim_leading("#comment\tcomment"), "");
1243 assert_eq!(trim_leading("#comment\n #comment2\n#comment\na"), "a");
1244 }
1245
1246 #[test]
1247 fn test_split_lines() {
1248 assert_eq!(split_lines("").collect::<Vec<_>>(), vec![""]);
1249 assert_eq!(split_lines("foo").collect::<Vec<_>>(), vec!["foo"]);
1250 assert_eq!(
1251 split_lines("foo\nbar").collect::<Vec<_>>(),
1252 vec!["foo", "bar"]
1253 );
1254 assert_eq!(
1255 split_lines("foo\nbar\nbaz").collect::<Vec<_>>(),
1256 vec!["foo", "bar", "baz"]
1257 );
1258
1259 assert_eq!(
1260 split_lines("foo\\nbar\nbaz").collect::<Vec<_>>(),
1261 vec!["foo\\nbar", "baz"]
1262 );
1263 assert_eq!(
1264 split_lines("meas tag=val field=1\nnext\n").collect::<Vec<_>>(),
1265 vec!["meas tag=val field=1", "next", ""]
1266 );
1267 assert_eq!(
1268 split_lines("meas tag=val field=\"\nval\"\nnext").collect::<Vec<_>>(),
1269 vec!["meas tag=val field=\"\nval\"", "next"]
1270 );
1271 assert_eq!(
1272 split_lines("meas tag=val field=\\\"\nval\"\nnext").collect::<Vec<_>>(),
1273 vec!["meas tag=val field=\\\"", "val\"", "next"]
1274 );
1275 assert_eq!(
1276 split_lines("meas tag=val field=1,field=\"\nval\"\nnext").collect::<Vec<_>>(),
1277 vec!["meas tag=val field=1,field=\"\nval\"", "next"]
1278 );
1279 assert_eq!(
1280 split_lines("meas tag=val field=1,field=\\\"\nval\"\nnext").collect::<Vec<_>>(),
1281 vec!["meas tag=val field=1,field=\\\"", "val\"", "next"]
1282 );
1283 }
1284
1285 #[test]
1286 fn escaped_str_multi_to_string() {
1287 let (_, es) = measurement("Foo\\aBar").unwrap();
1288 assert_eq!(es, "Foo\\aBar");
1290 }
1291
1292 fn parse(s: &str) -> Result<Vec<ParsedLine<'_>>, super::Error> {
1293 super::parse_lines(s).collect()
1294 }
1295
1296 #[test]
1297 fn parse_empty() {
1298 let input = "";
1299 let vals = parse(input);
1300 assert_eq!(vals.unwrap().len(), 0);
1301 }
1302
1303 #[test]
1305 fn parse_tag_no_value() {
1306 let input = "testmeasure,foo= bar=1i";
1307 let vals = parse(input);
1308 assert!(matches!(vals, Err(Error::TagSetMalformed)));
1309 }
1310
1311 #[test]
1313 fn parse_no_tagset() {
1314 let input = "testmeasure, bar=1i";
1315 let vals = parse(input);
1316 assert!(matches!(vals, Err(Error::TagSetMalformed)));
1317 }
1318
1319 #[test]
1320 fn parse_no_measurement() {
1321 let input = ",tag1=1,tag2=2 value=1 123";
1322 let vals = parse(input);
1323 assert!(matches!(vals, Err(Error::MeasurementValueInvalid)));
1324
1325 let input = "field=1 1234";
1327 let vals = parse(input);
1328 assert!(matches!(vals, Err(Error::FieldSetMissing)));
1329 }
1330
1331 #[test]
1333 fn parse_measurement_with_eq() {
1334 let input = "tag1=1 field=1 1234";
1335 let vals = parse(input);
1336 assert!(vals.is_ok());
1337
1338 let input = "tag1=1,tag2=2 value=1 123";
1339 let vals = parse(input);
1340 assert!(vals.is_ok());
1341 }
1342
1343 #[test]
1344 fn parse_null_measurement() {
1345 let input = "\0 field=1 1234";
1346 let vals = parse(input);
1347 assert!(matches!(vals, Err(Error::MeasurementValueInvalid)));
1348
1349 let input = "\0,tag1=1,tag2=2 value=1 123";
1350 let vals = parse(input);
1351 assert!(matches!(vals, Err(Error::MeasurementValueInvalid)));
1352 }
1353
1354 #[test]
1355 fn parse_where_nulls_accepted() {
1356 let input = "m,tag\x001=one,tag2=2 value=1 123
1357 m,tag1=o\0ne,tag2=2 value=1 123
1358 m,tag1=one,tag2=\0 value=1 123
1359 m,tag1=one,tag2=2 val\0ue=1 123
1360 m,tag1=one,tag2=2 value=\"v\0\" 123";
1361 let vals = parse(input);
1362 assert!(vals.is_ok());
1363 assert_eq!(vals.unwrap().len(), 5);
1364 }
1365
1366 #[test]
1367 fn parse_no_fields() {
1368 let input = "foo 1234";
1369 let vals = parse(input);
1370
1371 assert!(matches!(vals, Err(super::Error::FieldSetMissing)));
1372 }
1373
1374 #[test]
1375 fn parse_null_in_field_value() {
1376 let input = "m,tag1=one,tag2=2 value=\0 123";
1377 let vals = parse(input);
1378 assert!(vals.is_err());
1379 }
1380
1381 #[test]
1382 fn parse_single_field_integer() {
1383 let input = "foo asdf=23i 1234";
1384 let vals = parse(input).unwrap();
1385
1386 assert_eq!(vals[0].series.measurement, "foo");
1387 assert_eq!(vals[0].timestamp, Some(1234));
1388 assert_eq!(vals[0].field_set[0].0, "asdf");
1389 assert_eq!(vals[0].field_set[0].1.unwrap_i64(), 23);
1390 }
1391
1392 #[test]
1393 fn parse_single_field_unteger() {
1394 let input = "foo asdf=23u 1234";
1395 let vals = parse(input).unwrap();
1396
1397 assert_eq!(vals[0].series.measurement, "foo");
1398 assert_eq!(vals[0].timestamp, Some(1234));
1399 assert_eq!(vals[0].field_set[0].0, "asdf");
1400 assert_eq!(vals[0].field_set[0].1.unwrap_u64(), 23);
1401 }
1402
1403 #[test]
1404 fn parse_single_field_float_no_decimal() {
1405 let input = "foo asdf=44 546";
1406 let vals = parse(input).unwrap();
1407
1408 assert_eq!(vals[0].series.measurement, "foo");
1409 assert_eq!(vals[0].timestamp, Some(546));
1410 assert_eq!(vals[0].field_set[0].0, "asdf");
1411 assert!(approximately_equal(
1412 vals[0].field_set[0].1.unwrap_f64(),
1413 44.0
1414 ));
1415 }
1416
1417 #[test]
1418 fn parse_single_field_float_with_decimal() {
1419 let input = "foo asdf=3.74 123";
1420 let vals = parse(input).unwrap();
1421
1422 assert_eq!(vals[0].series.measurement, "foo");
1423 assert_eq!(vals[0].timestamp, Some(123));
1424 assert_eq!(vals[0].field_set[0].0, "asdf");
1425 assert!(approximately_equal(
1426 vals[0].field_set[0].1.unwrap_f64(),
1427 3.74
1428 ));
1429 }
1430
1431 #[test]
1432 fn parse_single_field_string() {
1433 let input = r#"foo asdf="the string value" 1234"#;
1434 let vals = parse(input).unwrap();
1435
1436 assert_eq!(vals[0].series.measurement, "foo");
1437 assert_eq!(vals[0].timestamp, Some(1234));
1438 assert_eq!(vals[0].field_set[0].0, "asdf");
1439 assert_eq!(&vals[0].field_set[0].1.unwrap_string(), "the string value");
1440 }
1441
1442 #[test]
1443 fn parse_single_field_bool() {
1444 let input = r#"foo asdf=true 1234"#;
1445 let vals = parse(input).unwrap();
1446
1447 assert_eq!(vals[0].series.measurement, "foo");
1448 assert_eq!(vals[0].timestamp, Some(1234));
1449 assert_eq!(vals[0].field_set[0].0, "asdf");
1450 assert!(vals[0].field_set[0].1.unwrap_bool());
1451 }
1452
1453 #[test]
1454 fn parse_string_values() {
1455 let test_data = vec![
1456 (r#"foo asdf="""#, ""),
1457 (r#"foo asdf="str val""#, "str val"),
1458 (r#"foo asdf="The \"string\" val""#, r#"The "string" val"#),
1459 (
1460 r#"foo asdf="The \"string w/ single double quote""#,
1461 r#"The "string w/ single double quote"#,
1462 ),
1463 (r#"foo asdf="too hot/cold""#, r#"too hot/cold"#),
1466 (r#"foo asdf="too hot\cold""#, r"too hot\cold"),
1467 (r#"foo asdf="too hot\\cold""#, r"too hot\cold"),
1468 (r#"foo asdf="too hot\\\cold""#, r"too hot\\cold"),
1469 (r#"foo asdf="too hot\\\\cold""#, r"too hot\\cold"),
1470 (r#"foo asdf="too hot\\\\\cold""#, r"too hot\\\cold"),
1471 ];
1472
1473 for (input, expected_parsed_string_value) in test_data {
1474 let vals = parse(input).unwrap();
1475 assert_eq!(vals[0].series.tag_set, None);
1476 assert_eq!(vals[0].field_set.len(), 1);
1477 assert_eq!(vals[0].field_set[0].0, "asdf");
1478 assert_eq!(
1479 &vals[0].field_set[0].1.unwrap_string(),
1480 expected_parsed_string_value
1481 );
1482 }
1483 }
1484
1485 #[test]
1486 fn parse_bool_values() {
1487 let test_data = vec![
1488 (r#"foo asdf=t"#, true),
1489 (r#"foo asdf=T"#, true),
1490 (r#"foo asdf=true"#, true),
1491 (r#"foo asdf=True"#, true),
1492 (r#"foo asdf=TRUE"#, true),
1493 (r#"foo asdf=f"#, false),
1494 (r#"foo asdf=F"#, false),
1495 (r#"foo asdf=false"#, false),
1496 (r#"foo asdf=False"#, false),
1497 (r#"foo asdf=FALSE"#, false),
1498 ];
1499
1500 for (input, expected_parsed_bool_value) in test_data {
1501 let vals = parse(input).unwrap();
1502 assert_eq!(vals[0].series.tag_set, None);
1503 assert_eq!(vals[0].field_set.len(), 1);
1504 assert_eq!(vals[0].field_set[0].0, "asdf");
1505 assert_eq!(
1506 vals[0].field_set[0].1.unwrap_bool(),
1507 expected_parsed_bool_value
1508 );
1509 }
1510 }
1511
1512 #[test]
1513 fn parse_two_fields_integer() {
1514 let input = "foo asdf=23i,bar=5i 1234";
1515 let vals = parse(input).unwrap();
1516
1517 assert_eq!(vals[0].series.measurement, "foo");
1518 assert_eq!(vals[0].timestamp, Some(1234));
1519
1520 assert_eq!(vals[0].field_set[0].0, "asdf");
1521 assert_eq!(vals[0].field_set[0].1.unwrap_i64(), 23);
1522
1523 assert_eq!(vals[0].field_set[1].0, "bar");
1524 assert_eq!(vals[0].field_set[1].1.unwrap_i64(), 5);
1525 }
1526
1527 #[test]
1528 fn parse_two_fields_unteger() {
1529 let input = "foo asdf=23u,bar=5u 1234";
1530 let vals = parse(input).unwrap();
1531
1532 assert_eq!(vals[0].series.measurement, "foo");
1533 assert_eq!(vals[0].timestamp, Some(1234));
1534
1535 assert_eq!(vals[0].field_set[0].0, "asdf");
1536 assert_eq!(vals[0].field_set[0].1.unwrap_u64(), 23);
1537
1538 assert_eq!(vals[0].field_set[1].0, "bar");
1539 assert_eq!(vals[0].field_set[1].1.unwrap_u64(), 5);
1540 }
1541
1542 #[test]
1543 fn parse_two_fields_float() {
1544 let input = "foo asdf=23.1,bar=5 1234";
1545 let vals = parse(input).unwrap();
1546
1547 assert_eq!(vals[0].series.measurement, "foo");
1548 assert_eq!(vals[0].timestamp, Some(1234));
1549
1550 assert_eq!(vals[0].field_set[0].0, "asdf");
1551 assert!(approximately_equal(
1552 vals[0].field_set[0].1.unwrap_f64(),
1553 23.1
1554 ));
1555
1556 assert_eq!(vals[0].field_set[1].0, "bar");
1557 assert!(approximately_equal(
1558 vals[0].field_set[1].1.unwrap_f64(),
1559 5.0
1560 ));
1561 }
1562
1563 #[test]
1564 fn parse_mixed_field_types() {
1565 let input = r#"foo asdf=23.1,bar=-5i,qux=9u,baz="the string",frab=false 1234"#;
1566 let vals = parse(input).unwrap();
1567
1568 assert_eq!(vals[0].series.measurement, "foo");
1569 assert_eq!(vals[0].timestamp, Some(1234));
1570
1571 assert_eq!(vals[0].field_set[0].0, "asdf");
1572 assert!(approximately_equal(
1573 vals[0].field_set[0].1.unwrap_f64(),
1574 23.1
1575 ));
1576
1577 assert_eq!(vals[0].field_set[1].0, "bar");
1578 assert_eq!(vals[0].field_set[1].1.unwrap_i64(), -5);
1579
1580 assert_eq!(vals[0].field_set[2].0, "qux");
1581 assert_eq!(vals[0].field_set[2].1.unwrap_u64(), 9);
1582
1583 assert_eq!(vals[0].field_set[3].0, "baz");
1584 assert_eq!(vals[0].field_set[3].1.unwrap_string(), "the string");
1585
1586 assert_eq!(vals[0].field_set[4].0, "frab");
1587 assert!(!vals[0].field_set[4].1.unwrap_bool());
1588 }
1589
1590 #[test]
1591 fn parse_negative_integer() {
1592 let input = "m0 field=-1i 99";
1593 let vals = parse(input).unwrap();
1594
1595 assert_eq!(vals.len(), 1);
1596 assert_eq!(vals[0].field_set[0].1.unwrap_i64(), -1);
1597 }
1598
1599 #[test]
1600 fn parse_negative_uinteger() {
1601 let input = "m0 field=-1u 99";
1602 let parsed = parse(input);
1603
1604 assert!(
1605 matches!(parsed, Err(super::Error::CannotParseEntireLine { .. })),
1606 "Wrong error: {parsed:?}",
1607 );
1608 }
1609
1610 #[test]
1611 fn parse_scientific_float() {
1612 let input = "m0 field=-1.234456e+06 1615869152385000000";
1614 let vals = parse(input).unwrap();
1615 assert_eq!(vals.len(), 1);
1616
1617 let input = "m0 field=-1.234456E+3 1615869152385000000";
1618 let vals = parse(input).unwrap();
1619 assert_eq!(vals.len(), 1);
1620
1621 let input = "m0 field=1.234456e+02 1615869152385000000";
1622 let vals = parse(input).unwrap();
1623 assert_eq!(vals.len(), 1);
1624
1625 let input = "m0 field=1.234456E+16 1615869152385000000";
1626 let vals = parse(input).unwrap();
1627 assert_eq!(vals.len(), 1);
1628
1629 let input = "m0 field=1.234456E-16";
1630 let vals = parse(input).unwrap();
1631 assert_eq!(vals.len(), 1);
1632
1633 let input = "m0 field=1.234456e-03";
1634 let vals = parse(input).unwrap();
1635 assert_eq!(vals.len(), 1);
1636
1637 let input = "m0 field=1.234456e-0";
1638 let vals = parse(input).unwrap();
1639 assert_eq!(vals.len(), 1);
1640
1641 let input = "m0 field=1e-0";
1642 let vals = parse(input).unwrap();
1643 assert_eq!(vals.len(), 1);
1644 assert_eq!(vals[0].field_value("field"), Some(&FieldValue::F64(1.0)));
1645
1646 let input = "m0 field=-1e-0";
1647 let vals = parse(input).unwrap();
1648 assert_eq!(vals.len(), 1);
1649 assert_eq!(vals[0].field_value("field"), Some(&FieldValue::F64(-1.0)));
1650
1651 let input = "m0 field=-1.234456e06 1615869152385000000";
1653 let vals = parse(input).unwrap();
1654 assert_eq!(vals.len(), 1);
1655 assert_float_field(&vals[0], "field", -1.234456e06);
1656
1657 let input = "m0 field=1.234456e06 1615869152385000000";
1658 let vals = parse(input).unwrap();
1659 assert_eq!(vals.len(), 1);
1660 assert_float_field(&vals[0], "field", 1.234456e06);
1661
1662 let input = "m0 field=-1.234456E06 1615869152385000000";
1663 let vals = parse(input).unwrap();
1664 assert_eq!(vals.len(), 1);
1665 assert_float_field(&vals[0], "field", -1.234456e06);
1666
1667 let input = "m0 field=1.234456E06 1615869152385000000";
1668 let vals = parse(input).unwrap();
1669 assert_eq!(vals.len(), 1);
1670 assert_float_field(&vals[0], "field", 1.234456e06);
1671
1672 let input = "m0 field=-1.234456e 1615869152385000000";
1677 let parsed = parse(input);
1678 assert!(
1679 matches!(parsed, Err(super::Error::CannotParseEntireLine { .. })),
1680 "Wrong error: {parsed:?}",
1681 );
1682
1683 let input = "m0 field=-1.234456e+ 1615869152385000000";
1684 let parsed = parse(input);
1685 assert!(
1686 matches!(parsed, Err(super::Error::CannotParseEntireLine { .. })),
1687 "Wrong error: {parsed:?}",
1688 );
1689
1690 let input = "m0 field=-1.234456E 1615869152385000000";
1691 let parsed = parse(input);
1692 assert!(
1693 matches!(parsed, Err(super::Error::CannotParseEntireLine { .. })),
1694 "Wrong error: {parsed:?}",
1695 );
1696
1697 let input = "m0 field=-1.234456E+ 1615869152385000000";
1698 let parsed = parse(input);
1699 assert!(
1700 matches!(parsed, Err(super::Error::CannotParseEntireLine { .. })),
1701 "Wrong error: {parsed:?}",
1702 );
1703
1704 let input = "m0 field=-1.234456E-";
1705 let parsed = parse(input);
1706 assert!(
1707 matches!(parsed, Err(super::Error::CannotParseEntireLine { .. })),
1708 "Wrong error: {parsed:?}",
1709 );
1710 }
1711
1712 #[test]
1713 fn parse_negative_float() {
1714 let input = "m0 field2=-1 99";
1715 let vals = parse(input).unwrap();
1716
1717 assert_eq!(vals.len(), 1);
1718 assert!(approximately_equal(
1719 vals[0].field_set[0].1.unwrap_f64(),
1720 -1.0
1721 ));
1722 }
1723
1724 #[test]
1725 fn parse_out_of_range_integer() {
1726 let input = "m0 field=99999999999999999999999999999999i 99";
1727 let parsed = parse(input);
1728
1729 assert!(
1730 matches!(parsed, Err(super::Error::IntegerValueInvalid { .. })),
1731 "Wrong error: {parsed:?}",
1732 );
1733 }
1734
1735 #[test]
1736 fn parse_out_of_range_uinteger() {
1737 let input = "m0 field=99999999999999999999999999999999u 99";
1738 let parsed = parse(input);
1739
1740 assert!(
1741 matches!(parsed, Err(super::Error::UIntegerValueInvalid { .. })),
1742 "Wrong error: {parsed:?}",
1743 );
1744 }
1745
1746 #[test]
1747 fn parse_out_of_range_float() {
1748 let input = format!("m0 field={val}.{val} 99", val = "9".repeat(200));
1750 let vals = parse(&input).unwrap();
1751
1752 assert_eq!(vals.len(), 1);
1753 assert!(approximately_equal(
1754 vals[0].field_set[0].1.unwrap_f64(),
1755 1e200f64
1756 ));
1757
1758 let input = format!("m0 field={val}.{val} 99", val = "9".repeat(1_000));
1760 let vals = parse(&input).unwrap();
1761
1762 assert_eq!(vals.len(), 1);
1763 assert!(vals[0].field_set[0].1.unwrap_f64().is_infinite());
1764 }
1765
1766 #[test]
1767 fn parse_tag_set_included_in_series() {
1768 let input = "foo,tag1=1,tag2=2 value=1 123";
1769 let vals = parse(input).unwrap();
1770
1771 assert_eq!(vals[0].series.measurement, "foo");
1772
1773 assert_eq!(vals[0].series.tag_set.as_ref().unwrap()[0].0, "tag1");
1774 assert_eq!(vals[0].series.tag_set.as_ref().unwrap()[0].1, "1");
1775
1776 assert_eq!(vals[0].series.tag_set.as_ref().unwrap()[1].0, "tag2");
1777 assert_eq!(vals[0].series.tag_set.as_ref().unwrap()[1].1, "2");
1778
1779 assert_eq!(vals[0].field_set[0].0, "value");
1780 }
1781
1782 #[test]
1783 fn parse_tag_set_unsorted() {
1784 let input = "foo,tag2=2,tag1=1";
1785 let (remaining, series) = series(input).unwrap();
1786
1787 assert!(remaining.is_empty());
1788 assert_eq!(series.generate_base().unwrap(), "foo,tag1=1,tag2=2");
1789 }
1790
1791 #[test]
1792 fn parse_tag_set_duplicate_tags() {
1793 let input = "foo,tag=1,tag=2";
1794 let (remaining, series) = series(input).unwrap();
1795
1796 assert!(remaining.is_empty());
1797 let err = series
1798 .generate_base()
1799 .expect_err("Parsing duplicate tags should fail");
1800
1801 assert_eq!(
1802 err.to_string(),
1803 r#"Must not contain duplicate tags, but "tag" was repeated"#
1804 );
1805 }
1806
1807 #[test]
1808 fn parse_multiple_lines_become_multiple_points() {
1809 let input = r#"foo value1=1i 123
1810foo value2=2i 123"#;
1811 let vals = parse(input).unwrap();
1812
1813 assert_eq!(vals[0].series.measurement, "foo");
1814 assert_eq!(vals[0].timestamp, Some(123));
1815 assert_eq!(vals[0].field_set[0].0, "value1");
1816 assert_eq!(vals[0].field_set[0].1.unwrap_i64(), 1);
1817
1818 assert_eq!(vals[1].series.measurement, "foo");
1819 assert_eq!(vals[1].timestamp, Some(123));
1820 assert_eq!(vals[1].field_set[0].0, "value2");
1821 assert_eq!(vals[1].field_set[0].1.unwrap_i64(), 2);
1822 }
1823
1824 #[test]
1825 fn parse_multiple_measurements_become_multiple_points() {
1826 let input = r#"foo value1=1i 123
1827bar value2=2i 123"#;
1828 let vals = parse(input).unwrap();
1829
1830 assert_eq!(vals[0].series.measurement, "foo");
1831 assert_eq!(vals[0].timestamp, Some(123));
1832 assert_eq!(vals[0].field_set[0].0, "value1");
1833 assert_eq!(vals[0].field_set[0].1.unwrap_i64(), 1);
1834
1835 assert_eq!(vals[1].series.measurement, "bar");
1836 assert_eq!(vals[1].timestamp, Some(123));
1837 assert_eq!(vals[1].field_set[0].0, "value2");
1838 assert_eq!(vals[1].field_set[0].1.unwrap_i64(), 2);
1839 }
1840
1841 #[test]
1842 fn parse_trailing_whitespace_is_fine() {
1843 let input = r#"foo,tag=val value1=1i 123
1844
1845"#;
1846 let vals = parse(input).unwrap();
1847 assert_eq!(vals.len(), 1);
1848
1849 assert_eq!(vals[0].series.measurement, "foo");
1850 assert_eq!(vals[0].timestamp, Some(123));
1851 assert_eq!(vals[0].field_set[0].0, "value1");
1852 assert_eq!(vals[0].field_set[0].1.unwrap_i64(), 1);
1853 }
1854
1855 #[test]
1856 fn parse_negative_timestamp() {
1857 let input = r#"foo value1=1i -123"#;
1858 let vals = parse(input).unwrap();
1859
1860 assert_eq!(vals[0].series.measurement, "foo");
1861 assert_eq!(vals[0].timestamp, Some(-123));
1862 assert_eq!(vals[0].field_set[0].0, "value1");
1863 assert_eq!(vals[0].field_set[0].1.unwrap_i64(), 1);
1864 }
1865
1866 #[test]
1867 fn parse_out_of_range_timestamp() {
1868 let input = "m0 field=1i 99999999999999999999999999999999";
1869 let parsed = parse(input);
1870
1871 assert!(
1872 matches!(parsed, Err(super::Error::TimestampValueInvalid { .. })),
1873 "Wrong error: {parsed:?}",
1874 );
1875 }
1876
1877 #[test]
1878 fn parse_blank_lines_are_ignored() {
1879 let input = "\n\n\n";
1880 let vals = parse(input).unwrap();
1881
1882 assert!(vals.is_empty());
1883 }
1884
1885 #[test]
1886 fn parse_commented_lines_are_ignored() {
1887 let input = "# comment";
1888 let vals = parse(input).unwrap();
1889
1890 assert!(vals.is_empty());
1891 }
1892
1893 #[test]
1894 fn parse_multiple_whitespace_between_elements_is_allowed() {
1895 let input = " measurement a=1i 123 ";
1896 let vals = parse(input).unwrap();
1897
1898 assert_eq!(vals[0].series.measurement, "measurement");
1899 assert_eq!(vals[0].timestamp, Some(123));
1900 assert_eq!(vals[0].field_set[0].0, "a");
1901 assert_eq!(vals[0].field_set[0].1.unwrap_i64(), 1);
1902 }
1903
1904 macro_rules! assert_fully_parsed {
1905 ($parse_result:expr, $output:expr $(,)?) => {{
1906 let (remaining, parsed) = $parse_result.unwrap();
1907
1908 assert!(
1909 remaining.is_empty(),
1910 "Some input remained to be parsed: {:?}",
1911 remaining,
1912 );
1913 assert_eq!(parsed, $output, "Did not parse the expected output");
1914 }};
1915 }
1916
1917 #[test]
1918 fn measurement_allows_escaping_comma() {
1919 assert_fully_parsed!(measurement(r"wea\,ther"), r#"wea,ther"#);
1920 }
1921
1922 #[test]
1923 fn measurement_allows_escaping_space() {
1924 assert_fully_parsed!(measurement(r"wea\ ther"), r#"wea ther"#);
1925 }
1926
1927 #[test]
1928 fn measurement_allows_escaping_backslash() {
1929 assert_fully_parsed!(measurement(r"\\wea\\ther"), r"\wea\ther");
1930 }
1931
1932 #[test]
1933 fn measurement_allows_backslash_with_unknown_escape() {
1934 assert_fully_parsed!(measurement(r"\wea\ther"), r"\wea\ther");
1935 }
1936
1937 #[test]
1938 fn measurement_allows_literal_newline_as_unknown_escape() {
1939 assert_fully_parsed!(
1940 measurement(
1941 r"weat\
1942her"
1943 ),
1944 "weat\\\nher",
1945 );
1946 }
1947
1948 #[test]
1949 fn measurement_disallows_literal_newline() {
1950 let (remaining, parsed) = measurement(
1951 r#"weat
1952her"#,
1953 )
1954 .unwrap();
1955 assert_eq!(parsed, "weat");
1956 assert_eq!(remaining, "\nher");
1957 }
1958
1959 #[test]
1960 fn measurement_disallows_ending_in_backslash() {
1961 let parsed = measurement(r"weather\");
1962 assert!(matches!(
1963 parsed,
1964 Err(nom::Err::Failure(super::Error::EndsWithBackslash))
1965 ));
1966 }
1967
1968 #[test]
1969 fn tag_key_allows_escaping_comma() {
1970 assert_fully_parsed!(tag_key(r"wea\,ther"), r#"wea,ther"#);
1971 }
1972
1973 #[test]
1974 fn tag_key_allows_escaping_equal() {
1975 assert_fully_parsed!(tag_key(r"wea\=ther"), r#"wea=ther"#);
1976 }
1977
1978 #[test]
1979 fn tag_key_allows_escaping_space() {
1980 assert_fully_parsed!(tag_key(r"wea\ ther"), r#"wea ther"#);
1981 }
1982
1983 #[test]
1984 fn tag_key_allows_escaping_backslash() {
1985 assert_fully_parsed!(tag_key(r"\\wea\\ther"), r"\wea\ther");
1986 }
1987
1988 #[test]
1989 fn tag_key_allows_backslash_with_unknown_escape() {
1990 assert_fully_parsed!(tag_key(r"\wea\ther"), r"\wea\ther");
1991 }
1992
1993 #[test]
1994 fn tag_key_allows_literal_newline_as_unknown_escape() {
1995 assert_fully_parsed!(
1996 tag_key(
1997 r"weat\
1998her"
1999 ),
2000 "weat\\\nher",
2001 );
2002 }
2003
2004 #[test]
2005 fn tag_key_disallows_literal_newline() {
2006 let (remaining, parsed) = tag_key(
2007 r#"weat
2008her"#,
2009 )
2010 .unwrap();
2011 assert_eq!(parsed, "weat");
2012 assert_eq!(remaining, "\nher");
2013 }
2014
2015 #[test]
2016 fn tag_key_disallows_ending_in_backslash() {
2017 let parsed = tag_key(r"weather\");
2018 assert!(matches!(
2019 parsed,
2020 Err(nom::Err::Failure(super::Error::EndsWithBackslash))
2021 ));
2022 }
2023
2024 #[test]
2025 fn tag_value_allows_escaping_comma() {
2026 assert_fully_parsed!(tag_value(r"wea\,ther"), r#"wea,ther"#);
2027 }
2028
2029 #[test]
2030 fn tag_value_allows_escaping_equal() {
2031 assert_fully_parsed!(tag_value(r"wea\=ther"), r#"wea=ther"#);
2032 }
2033
2034 #[test]
2035 fn tag_value_allows_escaping_space() {
2036 assert_fully_parsed!(tag_value(r"wea\ ther"), r#"wea ther"#);
2037 }
2038
2039 #[test]
2040 fn tag_value_allows_escaping_backslash() {
2041 assert_fully_parsed!(tag_value(r"\\wea\\ther"), r"\wea\ther");
2042 }
2043
2044 #[test]
2045 fn tag_value_allows_backslash_with_unknown_escape() {
2046 assert_fully_parsed!(tag_value(r"\wea\ther"), r"\wea\ther");
2047 }
2048
2049 #[test]
2050 fn tag_value_allows_literal_newline_as_unknown_escape() {
2051 assert_fully_parsed!(
2052 tag_value(
2053 r"weat\
2054her"
2055 ),
2056 "weat\\\nher",
2057 );
2058 }
2059
2060 #[test]
2061 fn tag_value_disallows_literal_newline() {
2062 let (remaining, parsed) = tag_value(
2063 r#"weat
2064her"#,
2065 )
2066 .unwrap();
2067 assert_eq!(parsed, "weat");
2068 assert_eq!(remaining, "\nher");
2069 }
2070
2071 #[test]
2072 fn tag_value_disallows_ending_in_backslash() {
2073 let parsed = tag_value(r"weather\");
2074 assert!(matches!(
2075 parsed,
2076 Err(nom::Err::Failure(super::Error::EndsWithBackslash))
2077 ));
2078 }
2079
2080 #[test]
2081 fn field_key_allows_escaping_comma() {
2082 assert_fully_parsed!(field_key(r"wea\,ther"), r#"wea,ther"#);
2083 }
2084
2085 #[test]
2086 fn field_key_allows_escaping_equal() {
2087 assert_fully_parsed!(field_key(r"wea\=ther"), r#"wea=ther"#);
2088 }
2089
2090 #[test]
2091 fn field_key_allows_escaping_space() {
2092 assert_fully_parsed!(field_key(r"wea\ ther"), r#"wea ther"#);
2093 }
2094
2095 #[test]
2096 fn field_key_allows_escaping_backslash() {
2097 assert_fully_parsed!(field_key(r"\\wea\\ther"), r"\wea\ther");
2098 }
2099
2100 #[test]
2101 fn field_key_allows_backslash_with_unknown_escape() {
2102 assert_fully_parsed!(field_key(r"\wea\ther"), r"\wea\ther");
2103 }
2104
2105 #[test]
2106 fn field_key_allows_literal_newline_as_unknown_escape() {
2107 assert_fully_parsed!(
2108 field_key(
2109 r"weat\
2110her"
2111 ),
2112 "weat\\\nher",
2113 );
2114 }
2115
2116 #[test]
2117 fn field_key_disallows_literal_newline() {
2118 let (remaining, parsed) = field_key(
2119 r#"weat
2120her"#,
2121 )
2122 .unwrap();
2123 assert_eq!(parsed, "weat");
2124 assert_eq!(remaining, "\nher");
2125 }
2126
2127 #[test]
2128 fn field_key_disallows_ending_in_backslash() {
2129 let parsed = field_key(r"weather\");
2130 assert!(matches!(
2131 parsed,
2132 Err(nom::Err::Failure(super::Error::EndsWithBackslash))
2133 ));
2134 }
2135
2136 #[test]
2137 fn parse_no_time() {
2138 let input = "foo,tag0=value1 asdf=23.1,bar=5i";
2139 let vals = parse(input).unwrap();
2140
2141 assert_eq!(vals[0].series.measurement, "foo");
2142 assert_eq!(vals[0].series.tag_set.as_ref().unwrap()[0].0, "tag0");
2143 assert_eq!(vals[0].series.tag_set.as_ref().unwrap()[0].1, "value1");
2144
2145 assert_eq!(vals[0].timestamp, None);
2146
2147 assert_eq!(vals[0].field_set[0].0, "asdf");
2148 assert!(approximately_equal(
2149 vals[0].field_set[0].1.unwrap_f64(),
2150 23.1
2151 ));
2152
2153 assert_eq!(vals[0].field_set[1].0, "bar");
2154 assert_eq!(vals[0].field_set[1].1.unwrap_i64(), 5);
2155 }
2156
2157 #[test]
2158 fn parse_advance_after_error() {
2159 let input = "foo,tag0=value1 asdf=23.1.22,jkl=4\n\
2162 foo,tag0=value2 asdf=22.1,jkl=5";
2163
2164 let vals: Vec<_> = super::parse_lines(input).collect();
2165
2166 assert_eq!(vals.len(), 2);
2167 assert!(vals[0].is_err());
2168 assert_eq!(
2169 format!("{:?}", &vals[0]),
2170 "Err(CannotParseEntireLine { trailing_content: \".22,jkl=4\" })"
2171 );
2172
2173 assert!(vals[1].is_ok());
2174 let parsed_line = vals[1].as_ref().expect("second line succeeded");
2175 assert_eq!(parsed_line.series.measurement, "foo");
2176 assert_eq!(parsed_line.series.tag_set.as_ref().unwrap()[0].0, "tag0");
2177 assert_eq!(parsed_line.series.tag_set.as_ref().unwrap()[0].1, "value2");
2178
2179 assert_eq!(parsed_line.timestamp, None);
2180
2181 assert_eq!(parsed_line.field_set[0].0, "asdf");
2182 assert!(approximately_equal(
2183 parsed_line.field_set[0].1.unwrap_f64(),
2184 22.1
2185 ));
2186
2187 assert_eq!(parsed_line.field_set[1].0, "jkl");
2188 assert!(approximately_equal(
2189 parsed_line.field_set[1].1.unwrap_f64(),
2190 5.
2191 ));
2192 }
2193
2194 #[test]
2195 fn field_value_display() {
2196 assert_eq!(FieldValue::I64(-42).to_string(), "-42i");
2197 assert_eq!(FieldValue::U64(42).to_string(), "42u");
2198 assert_eq!(FieldValue::F64(42.11).to_string(), "42.11");
2199 assert_eq!(
2200 FieldValue::String(EscapedStr::from("foo")).to_string(),
2201 "foo"
2202 );
2203 assert_eq!(FieldValue::Boolean(true).to_string(), "true");
2204 assert_eq!(FieldValue::Boolean(false).to_string(), "false");
2205 }
2206
2207 #[test]
2208 fn series_display_no_tags() {
2209 let series = Series {
2210 raw_input: "foo",
2211 measurement: EscapedStr::from("m"),
2212 tag_set: None,
2213 };
2214 assert_eq!(series.to_string(), "m");
2215 }
2216
2217 #[test]
2218 fn series_display_one_tag() {
2219 let series = Series {
2220 raw_input: "foo",
2221 measurement: EscapedStr::from("m"),
2222 tag_set: Some(smallvec![(
2223 EscapedStr::from("tag1"),
2224 EscapedStr::from("val1")
2225 )]),
2226 };
2227 assert_eq!(series.to_string(), "m,tag1=val1");
2228 }
2229
2230 #[test]
2231 fn series_display_two_tags() {
2232 let series = Series {
2233 raw_input: "foo",
2234 measurement: EscapedStr::from("m"),
2235 tag_set: Some(smallvec![
2236 (EscapedStr::from("tag1"), EscapedStr::from("val1")),
2237 (EscapedStr::from("tag2"), EscapedStr::from("val2")),
2238 ]),
2239 };
2240 assert_eq!(series.to_string(), "m,tag1=val1,tag2=val2");
2241 }
2242
2243 #[test]
2244 fn parsed_line_display_one_field_no_timestamp() {
2245 let series = Series {
2246 raw_input: "foo",
2247 measurement: EscapedStr::from("m"),
2248 tag_set: Some(smallvec![(
2249 EscapedStr::from("tag1"),
2250 EscapedStr::from("val1")
2251 ),]),
2252 };
2253 let field_set = smallvec![(EscapedStr::from("field1"), FieldValue::F64(42.1))];
2254
2255 let parsed_line = ParsedLine {
2256 series,
2257 field_set,
2258 timestamp: None,
2259 };
2260
2261 assert_eq!(parsed_line.to_string(), "m,tag1=val1 field1=42.1");
2262 }
2263
2264 #[test]
2265 fn parsed_line_display_one_field_timestamp() {
2266 let series = Series {
2267 raw_input: "foo",
2268 measurement: EscapedStr::from("m"),
2269 tag_set: Some(smallvec![(
2270 EscapedStr::from("tag1"),
2271 EscapedStr::from("val1")
2272 ),]),
2273 };
2274 let field_set = smallvec![(EscapedStr::from("field1"), FieldValue::F64(42.1))];
2275
2276 let parsed_line = ParsedLine {
2277 series,
2278 field_set,
2279 timestamp: Some(33),
2280 };
2281
2282 assert_eq!(parsed_line.to_string(), "m,tag1=val1 field1=42.1 33");
2283 }
2284
2285 #[test]
2286 fn parsed_line_display_two_fields_timestamp() {
2287 let series = Series {
2288 raw_input: "foo",
2289 measurement: EscapedStr::from("m"),
2290 tag_set: Some(smallvec![(
2291 EscapedStr::from("tag1"),
2292 EscapedStr::from("val1")
2293 ),]),
2294 };
2295 let field_set = smallvec![
2296 (EscapedStr::from("field1"), FieldValue::F64(42.1)),
2297 (EscapedStr::from("field2"), FieldValue::Boolean(false)),
2298 ];
2299
2300 let parsed_line = ParsedLine {
2301 series,
2302 field_set,
2303 timestamp: Some(33),
2304 };
2305
2306 assert_eq!(
2307 parsed_line.to_string(),
2308 "m,tag1=val1 field1=42.1,field2=false 33"
2309 );
2310 }
2311
2312 #[test]
2313 fn parsed_line_display_escaped() {
2314 let series = Series {
2315 raw_input: "foo",
2316 measurement: EscapedStr::from("m,and m"),
2317 tag_set: Some(smallvec![(
2318 EscapedStr::from("tag ,1"),
2319 EscapedStr::from("val ,1")
2320 ),]),
2321 };
2322 let field_set = smallvec![(
2323 EscapedStr::from("field ,1"),
2324 FieldValue::String(EscapedStr::from("Foo\"Bar"))
2325 ),];
2326
2327 let parsed_line = ParsedLine {
2328 series,
2329 field_set,
2330 timestamp: Some(33),
2331 };
2332
2333 assert_eq!(
2334 parsed_line.to_string(),
2335 r#"m\,and\ m,tag\ \,1=val\ \,1 field\ \,1=Foo\"Bar 33"#
2336 );
2337 }
2338
2339 #[test]
2340 fn field_value_returned() {
2341 let input = r#"foo asdf=true 1234"#;
2342 let vals = parse(input).unwrap();
2343
2344 assert!(vals[0].field_value("asdf").unwrap().unwrap_bool());
2345 }
2346
2347 #[test]
2348 fn field_value_missing() {
2349 let input = r#"foo asdf=true 1234"#;
2350 let vals = parse(input).unwrap();
2351
2352 assert_eq!(vals[0].field_value("jkl"), None);
2353 }
2354
2355 #[test]
2356 fn tag_value_returned() {
2357 let input = r#"foo,test=stuff asdf=true 1234"#;
2358 let vals = parse(input).unwrap();
2359
2360 assert_eq!(*vals[0].tag_value("test").unwrap(), "stuff");
2361 }
2362
2363 #[test]
2364 fn tag_value_missing() {
2365 let input = r#"foo,test=stuff asdf=true 1234"#;
2366 let vals = parse(input).unwrap();
2367
2368 assert_eq!(vals[0].tag_value("asdf"), None);
2369 }
2370
2371 #[test]
2372 fn test_field_value_same_type() {
2373 assert!(FieldValue::I64(0).is_same_type(&FieldValue::I64(42)));
2375 assert!(FieldValue::U64(0).is_same_type(&FieldValue::U64(42)));
2376 assert!(FieldValue::F64(0.0).is_same_type(&FieldValue::F64(4.2)));
2377 assert!(
2379 FieldValue::String(EscapedStr::CopiedValue("bananas".to_string())).is_same_type(
2380 &FieldValue::String(EscapedStr::CopiedValue("platanos".to_string()))
2381 )
2382 );
2383 assert!(FieldValue::String(EscapedStr::SingleSlice("bananas"))
2385 .is_same_type(&FieldValue::String(EscapedStr::SingleSlice("platanos"))));
2386 assert!(
2388 FieldValue::String(EscapedStr::SingleSlice("bananas")).is_same_type(
2389 &FieldValue::String(EscapedStr::CopiedValue("platanos".to_string()))
2390 )
2391 );
2392
2393 assert!(FieldValue::Boolean(true).is_same_type(&FieldValue::Boolean(false)));
2394
2395 assert!(!FieldValue::I64(0).is_same_type(&FieldValue::U64(42)));
2397 assert!(!FieldValue::U64(0).is_same_type(&FieldValue::I64(42)));
2398 assert!(!FieldValue::F64(0.0).is_same_type(&FieldValue::U64(42)));
2399 assert!(
2400 !FieldValue::String(EscapedStr::CopiedValue("bananas".to_string()))
2401 .is_same_type(&FieldValue::U64(42))
2402 );
2403 assert!(!FieldValue::Boolean(true).is_same_type(&FieldValue::U64(42)));
2404 }
2405
2406 fn assert_float_field(parsed_line: &ParsedLine<'_>, field_name: &str, expected_value: f64) {
2409 let field_value = parsed_line
2410 .field_value(field_name)
2411 .expect("did not contain field name");
2412
2413 let actual_value = if let FieldValue::F64(v) = field_value {
2414 *v
2415 } else {
2416 panic!("field {field_name} had value {field_value:?}, expected F64");
2417 };
2418
2419 assert!(approximately_equal(expected_value, actual_value));
2420 }
2421}