iflet Some(c) = parser.peek() { if c != b',' { return Err(error::Repr::TrailingCharactersAfterMember(parser.index));
}
parser.next();
}
parser.consume_ows_chars();
if parser.peek().is_none() { // Report the error at the position of the comma itself, rather // than at the end of input. return Err(error::Repr::TrailingComma(comma_index));
}
}
Ok(())
}
/// Exposes methods for parsing input into a structured field value. #[must_use] pubstruct Parser<'de> {
input: &'de [u8],
index: usize,
version: Version,
}
impl<'de> Parser<'de> { /// Creates a parser from the given input with [`Version::Rfc9651`]. pubfn new(input: &'de (impl ?Sized + AsRef<[u8]>)) -> Self { Self {
input: input.as_ref(),
index: 0,
version: Version::Rfc9651,
}
}
/// Sets the parser's version and returns it. pubfn with_version(mutself, version: Version) -> Self { self.version = version; self
}
/// Parses a structured field value. /// /// # Errors /// When the parsing process is unsuccessful. #[cfg(feature = "parsed-types")] pubfn parse<T: crate::FieldType>(self) -> SFVResult<T> {
T::parse(self)
}
/// Parses input into a structured field value of `Dictionary` type, using /// the given visitor. #[cfg_attr(
feature = "parsed-types",
doc = r#"
This can also be used to parse a dictionary that is split into multiple lines by merging
them into an existing structure:
assert_eq!(
dict.serialize().as_deref(),
Some("a=1, b=2"),
); # Ok(()) # }
``` "#
)] /// /// # Errors /// When the parsing process is unsuccessful, including any error raised by a visitor. pubfn parse_dictionary_with_visitor( self,
visitor: &mut (impl ?Sized + DictionaryVisitor<'de>),
) -> SFVResult<()> { // https://httpwg.org/specs/rfc9651.html#parse-dictionary self.parse_internal(move |parser| {
parse_comma_separated(parser, |parser| { // Note: It is up to the visitor to properly handle duplicate keys. let entry_visitor = visitor.entry(parser.parse_key()?)?;
/// Parses input into a structured field value of `List` type, using the /// given visitor. #[allow(clippy::needless_raw_string_hashes)] // false positive: https://github.com/rust-lang/rust-clippy/issues/11737 #[cfg_attr(
feature = "parsed-types",
doc = r##"
This can also be used to parse a list that is split into multiple lines by merging them
into an existing structure:
``` # use sfv::{FieldType, List, Parser}; # fn main() -> Result<(), sfv::Error> { letmut list: List = Parser::new("11, (12 13)").parse()?;
assert_eq!(
list.serialize().as_deref(),
Some(r#"11, (1213), "foo", "bar""#),
); # Ok(()) # }
``` "##
)] /// /// # Errors /// When the parsing process is unsuccessful, including any error raised by a visitor. pubfn parse_list_with_visitor( self,
visitor: &mut (impl ?Sized + ListVisitor<'de>),
) -> SFVResult<()> { // https://httpwg.org/specs/rfc9651.html#parse-list self.parse_internal(|parser| {
parse_comma_separated(parser, |parser| parser.parse_list_entry(visitor.entry()?))
})
}
/// Parses input into a structured field value of `Item` type, using the /// given visitor. /// /// # Errors /// When the parsing process is unsuccessful, including any error raised by a visitor. pubfn parse_item_with_visitor(self, visitor: impl ItemVisitor<'de>) -> SFVResult<()> { self.parse_internal(|parser| parse_item(parser, visitor))
}
loop { matchself.peek() {
Some(c) if is_allowed_inner_char(c) => { self.next();
} // TODO: The UTF-8 validation is redundant with the preceding character checks, but // its removal is only possible with unsafe code.
_ => return Some(std::str::from_utf8(&self.input[start..self.index]).unwrap()),
}
}
}
match base64::Engine::decode(&utils::BASE64, &self.input[start..colon_index]) {
Ok(content) => Ok(content),
Err(err) => { let index = match err {
base64::DecodeError::InvalidByte(offset, _)
| base64::DecodeError::InvalidLastSymbol(offset, _) => start + offset, // Report these two at the position of the last base64 // character, since they correspond to errors in the input // as a whole.
base64::DecodeError::InvalidLength(_) | base64::DecodeError::InvalidPadding => {
colon_index - 1
}
};
if scale == 100 { // Report the error at the position of the decimal itself, rather // than the next position.
Err(error::Repr::TrailingDecimalPoint(self.index - 1))
} else {
Ok(Num::Decimal(Decimal::from_integer_scaled_1000(
Integer::try_from(sign * magnitude).unwrap(),
)))
}
}
let param_name = self.parse_key()?; let param_value = matchself.peek() {
Some(b'=') => { self.next(); self.parse_bare_item()?
}
_ => BareItemFromInput::Boolean(true),
}; // Note: It is up to the visitor to properly handle duplicate keys.
visitor.parameter(param_name, param_value)?;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.