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 }