-
Notifications
You must be signed in to change notification settings - Fork 1
Pp refresh #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Pp refresh #3
Changes from all commits
7ea839f
eaf0ea7
643a78c
d70aee6
066c93f
a546c25
84812d8
727ddb0
9928960
6b4b6f1
cf890d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,40 +1,51 @@ | ||
| use std::str::FromStr; | ||
|
|
||
| use serde::de::{Visitor, IntoDeserializer}; | ||
| use serde::de::value::MapDeserializer; | ||
| use serde::de::{IntoDeserializer, Visitor}; | ||
|
|
||
| use regex::Regex; | ||
|
|
||
| use crate::error::*; | ||
|
|
||
| pub(crate) struct Deserializer<'de> { | ||
| pub struct Deserializer<'de> { | ||
| input: &'de str, | ||
| regex: Regex, | ||
| } | ||
|
|
||
| impl<'de> Deserializer<'de> { | ||
| pub fn new(input: &'de str, regex: Regex) -> Deserializer { | ||
| Deserializer { | ||
| input, | ||
| regex, | ||
| } | ||
| pub const fn new(input: &'de str, regex: Regex) -> Deserializer { | ||
| Deserializer { input, regex } | ||
| } | ||
| } | ||
|
|
||
| impl<'de, 'a> serde::Deserializer<'de> for &'a mut Deserializer<'de> { | ||
| impl<'de> serde::Deserializer<'de> for &'_ mut Deserializer<'de> { | ||
| type Error = Error; | ||
|
|
||
| fn deserialize_any<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| #[inline] | ||
| fn deserialize_any<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| self.deserialize_map(visitor) | ||
| } | ||
|
|
||
| fn deserialize_map<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| let caps = self.regex.captures(&self.input).ok_or_else(Error::NoMatch)?; | ||
| fn deserialize_map<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| let caps = self.regex.captures(self.input).ok_or_else(Error::NoMatch)?; | ||
|
|
||
| let items = self.regex.capture_names().filter_map(|n| { | ||
| n.map(|name| { | ||
| let value = &caps[name]; | ||
| (name.to_owned(), Value { name: name.to_owned(), value: value.to_owned() }) | ||
| n.and_then(|name| { | ||
| caps.name(name).map(|value| { | ||
| ( | ||
| name.to_owned(), | ||
| Value { | ||
| name: name.to_owned(), | ||
| value: value.as_str().to_owned(), | ||
| }, | ||
| ) | ||
| }) | ||
| }) | ||
| }); | ||
|
|
||
|
|
@@ -54,14 +65,17 @@ impl<'de, 'a> serde::Deserializer<'de> for &'a mut Deserializer<'de> { | |
| } | ||
| } | ||
|
|
||
|
|
||
| struct Value { | ||
| name: String, | ||
| value: String, | ||
| } | ||
|
|
||
| impl Value { | ||
| fn parse<T>(&self) -> Result<T> where T: FromStr { | ||
| #[allow(clippy::map_err_ignore)] | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's better to not ignore this error and make the parser error available in the caller instead of ignoring this problem... |
||
| fn parse<T>(&self) -> Result<T> | ||
| where | ||
| T: FromStr, | ||
| { | ||
| self.value.parse().map_err(|_| self.get_parse_error()) | ||
| } | ||
|
|
||
|
|
@@ -84,11 +98,17 @@ impl<'de> IntoDeserializer<'de, Error> for Value { | |
| impl<'de> serde::Deserializer<'de> for Value { | ||
| type Error = Error; | ||
|
|
||
| fn deserialize_any<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_any<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| self.value.into_deserializer().deserialize_any(visitor) | ||
| } | ||
|
|
||
| fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| if self.value.eq_ignore_ascii_case("true") { | ||
| visitor.visit_bool(true) | ||
| } else if self.value.eq_ignore_ascii_case("false") { | ||
|
|
@@ -98,59 +118,103 @@ impl<'de> serde::Deserializer<'de> for Value { | |
| } | ||
| } | ||
|
|
||
| fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_i8(self.parse()?) | ||
| } | ||
|
|
||
| fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_i16(self.parse()?) | ||
| } | ||
|
|
||
| fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_i32(self.parse()?) | ||
| } | ||
|
|
||
| fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_i64(self.parse()?) | ||
| } | ||
|
|
||
| fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_u8(self.parse()?) | ||
| } | ||
|
|
||
| fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_u16(self.parse()?) | ||
| } | ||
|
|
||
| fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_u32(self.parse()?) | ||
| } | ||
|
|
||
| fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_u64(self.parse()?) | ||
| } | ||
|
|
||
| fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_f32(self.parse()?) | ||
| } | ||
|
|
||
| fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_f64(self.parse()?) | ||
| } | ||
|
|
||
| fn deserialize_option<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_option<V>(self, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| if self.value.is_empty() { | ||
| visitor.visit_none() | ||
| } else { | ||
| visitor.visit_some(self) | ||
| } | ||
| } | ||
|
|
||
| fn deserialize_newtype_struct<V>(self, _: &'static str, visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_newtype_struct<V>(self, _: &'static str, visitor: V) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_newtype_struct(self) | ||
| } | ||
|
|
||
| fn deserialize_enum<V>(self, _name: &'static str, _variants: &'static [&'static str], visitor: V) -> Result<V::Value> where V: Visitor<'de> { | ||
| fn deserialize_enum<V>( | ||
| self, | ||
| _name: &'static str, | ||
| _variants: &'static [&'static str], | ||
| visitor: V, | ||
| ) -> Result<V::Value> | ||
| where | ||
| V: Visitor<'de>, | ||
| { | ||
| visitor.visit_enum(self.value.into_deserializer()) | ||
| } | ||
|
|
||
|
|
@@ -160,4 +224,4 @@ impl<'de> serde::Deserializer<'de> for Value { | |
| unit seq bytes byte_buf map unit_struct | ||
| tuple_struct tuple ignored_any struct | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ use std::fmt::{Display, Formatter}; | |
|
|
||
| /// An error that occurred during deserialization. | ||
| #[derive(Debug)] | ||
| #[non_exhaustive] | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't think we should do this. Marking an error enum as non exhaustive makes some devs more lazy about error handling and there should be a good reason for doing this. The error handling of this crate is already quite weak and in would be better to improve this instead of allowing users to ignore errors. |
||
| pub enum Error { | ||
| /// An error occurred while parsing the regular expression | ||
| BadRegex(regex::Error), | ||
|
|
@@ -23,25 +24,35 @@ pub enum Error { | |
| } | ||
|
|
||
| impl serde::de::Error for Error { | ||
| fn custom<T>(msg: T) -> Self where T: Display { | ||
| #[inline] | ||
| fn custom<T>(msg: T) -> Self | ||
| where | ||
| T: Display, | ||
| { | ||
| Self::Custom(msg.to_string()) | ||
| } | ||
| } | ||
|
|
||
| impl std::error::Error for Error {} | ||
|
|
||
| impl Display for Error { | ||
| #[inline] | ||
| fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
| use Error::*; | ||
| match self { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This make the code more difficult to read without any benefit. |
||
| BadRegex(err) => err.fmt(f), | ||
| match *self { | ||
| BadRegex(ref err) => err.fmt(f), | ||
| NoMatch() => write!(f, "String doesn't match pattern"), | ||
| BadValue { name, value } => write!(f, "Unable to convert value for group {}: {}", name, value), | ||
| Custom(err) => write!(f, "{}", err), | ||
| BadValue { | ||
| ref name, | ||
| ref value, | ||
| } => { | ||
| write!(f, "Unable to convert value for group {}: {}", name, value) | ||
| } | ||
| Custom(ref err) => write!(f, "{}", err), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Do not use this alias in public parts of the crate because | ||
| // it would hide the direct link to the actual error type in rustdoc. | ||
| pub(crate) type Result<T> = std::result::Result<T, Error>; | ||
| pub type Result<T> = std::result::Result<T, Error>; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a good use-case for making this const?
AFAIK creating a Regex isn't possible in a const context anyways.