/ src / types.rs
types.rs
  1  use crate::error::Error;
  2  use std::borrow::Cow;
  3  use std::ops::Range;
  4  
  5  // ==================================================================================
  6  //  Configuration
  7  // ==================================================================================
  8  
  9  #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
 10  pub struct ParseOptions {
 11      pub include_comments: bool,
 12      pub track_positions: bool,
 13  }
 14  
 15  impl ParseOptions {
 16      pub fn fast() -> Self {
 17          Self::default()
 18      }
 19  
 20      pub fn full() -> Self {
 21          Self {
 22              include_comments: true,
 23              track_positions: true,
 24          }
 25      }
 26  }
 27  
 28  // ==================================================================================
 29  //  Position & Spans
 30  // ==================================================================================
 31  
 32  #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
 33  pub struct Position {
 34      pub offset: usize,
 35  }
 36  
 37  impl Position {
 38      #[inline]
 39      pub fn from_offset(offset: usize) -> Self {
 40          Self { offset }
 41      }
 42  }
 43  
 44  #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
 45  pub struct Span {
 46      pub start: Position,
 47      pub end: Position,
 48  }
 49  
 50  impl Span {
 51      #[inline]
 52      pub fn new(start: Position, end: Position) -> Self {
 53          Self { start, end }
 54      }
 55  
 56      #[inline]
 57      pub fn from_offsets(start: usize, end: usize) -> Self {
 58          Self {
 59              start: Position::from_offset(start),
 60              end: Position::from_offset(end),
 61          }
 62      }
 63  
 64      pub fn len(&self) -> usize {
 65          self.end.offset - self.start.offset
 66      }
 67  
 68      pub fn is_empty(&self) -> bool {
 69          self.len() == 0
 70      }
 71  
 72      pub fn range(&self) -> Range<usize> {
 73          self.start.offset..self.end.offset
 74      }
 75  }
 76  
 77  // ==================================================================================
 78  //  Data Models
 79  // ==================================================================================
 80  
 81  #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
 82  pub enum QuoteType {
 83      Single, // '
 84      Double, // "
 85      #[default]
 86      None, // No quotes
 87  }
 88  
 89  #[derive(Debug, Clone, PartialEq, Eq)]
 90  pub enum Entry<'a> {
 91      Comment(Span),
 92      Pair(Box<KeyValuePair<'a>>),
 93      Error(Error),
 94  }
 95  
 96  impl<'a> Entry<'a> {
 97      pub fn as_pair(&self) -> Option<&KeyValuePair> {
 98          match self {
 99              Entry::Pair(kv) => Some(kv),
100              _ => None,
101          }
102      }
103  
104      pub fn into_owned(self) -> Entry<'static> {
105          match self {
106              Entry::Pair(kv) => Entry::Pair(Box::new(kv.into_owned())),
107              Entry::Comment(span) => Entry::Comment(span),
108              Entry::Error(e) => Entry::Error(e),
109          }
110      }
111  }
112  
113  #[derive(Debug, Clone, PartialEq, Eq)]
114  pub struct KeyValuePair<'a> {
115      pub key: Cow<'a, str>,
116      pub key_span: Option<Span>,
117  
118      pub value: Cow<'a, str>,
119      pub value_span: Option<Span>,
120  
121      pub quote: QuoteType,
122      pub open_quote_pos: Option<Position>,
123      pub close_quote_pos: Option<Position>,
124      pub equals_pos: Option<Position>,
125  
126      pub is_exported: bool,
127      pub export_span: Option<Span>,
128      pub is_comment: bool,
129  }
130  
131  impl<'a> KeyValuePair<'a> {
132      #[inline]
133      pub fn new_fast(
134          key: impl Into<Cow<'a, str>>,
135          value: Cow<'a, str>,
136          quote: QuoteType,
137          is_exported: bool,
138          is_comment: bool,
139      ) -> Self {
140          Self {
141              key: key.into(),
142              key_span: None,
143              value,
144              value_span: None,
145              quote,
146              open_quote_pos: None,
147              close_quote_pos: None,
148              equals_pos: None,
149              is_exported,
150              export_span: None,
151              is_comment,
152          }
153      }
154  
155      #[inline]
156      #[allow(clippy::too_many_arguments)]
157      pub fn new(
158          key: &'a str,
159          key_start: usize,
160          value: Cow<'a, str>,
161          value_start: usize,
162          raw_len: usize,
163          quote: QuoteType,
164          is_exported: bool,
165          export_span: Option<Span>,
166          is_comment: bool,
167      ) -> Self {
168          let key_end = key_start + key.len();
169          let value_end = value_start + raw_len;
170  
171          Self {
172              key: Cow::Borrowed(key),
173              key_span: Some(Span::from_offsets(key_start, key_end)),
174              value,
175              value_span: Some(Span::from_offsets(value_start, value_end)),
176              quote,
177              open_quote_pos: if quote != QuoteType::None {
178                  Some(Position::from_offset(value_start))
179              } else {
180                  None
181              },
182              close_quote_pos: if quote != QuoteType::None {
183                  Some(Position::from_offset(value_end - 1))
184              } else {
185                  None
186              },
187              equals_pos: Some(Position::from_offset(key_end)), // '=' is right after key
188              is_exported,
189              export_span,
190              is_comment,
191          }
192      }
193  
194      pub fn into_owned(self) -> KeyValuePair<'static> {
195          KeyValuePair {
196              key: Cow::Owned(self.key.into_owned()),
197              key_span: self.key_span,
198              value: Cow::Owned(self.value.into_owned()),
199              value_span: self.value_span,
200              quote: self.quote,
201              open_quote_pos: self.open_quote_pos,
202              close_quote_pos: self.close_quote_pos,
203              equals_pos: self.equals_pos,
204              is_exported: self.is_exported,
205              export_span: self.export_span,
206              is_comment: self.is_comment,
207          }
208      }
209  }