Skip to content

Commit

Permalink
Simplify implementation of the deserializer
Browse files Browse the repository at this point in the history
  • Loading branch information
nilehmann committed Jul 7, 2024
1 parent 488c5d0 commit d3b48db
Showing 1 changed file with 37 additions and 55 deletions.
92 changes: 37 additions & 55 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::fs;
use std::io::{BufRead, BufReader, Read};
use std::process::{Command, Stdio};
Expand Down Expand Up @@ -175,7 +176,7 @@ enum Filter {
Span {
begin: Regex,
end: Option<Regex>,
in_section: bool,
inside: bool,
},
}

Expand All @@ -186,21 +187,15 @@ impl Filter {
Filter::Span {
begin: start,
end,
in_section,
inside,
} => {
if *in_section {
let Some(end) = end else {
return true;
};
if end.is_match(s) {
*in_section = false;
}
if *inside {
let Some(end) = end else { return true };
*inside = !end.is_match(s);
true
} else {
if start.is_match(s) {
*in_section = true;
}
*in_section
*inside = start.is_match(s);
*inside
}
}
}
Expand All @@ -216,73 +211,60 @@ impl TryFrom<&HideConfig> for Filter {
HideConfig::Span { begin, end } => Filter::Span {
begin: begin.as_str().try_into()?,
end: end.as_deref().map(Regex::try_from).transpose()?,
in_section: false,
inside: false,
},
};
Ok(filter)
}
}

// Unfortunately we have to implement our own deserializer.
// See https://github.com/toml-rs/toml/issues/748 and https://github.com/toml-rs/toml/issues/535
impl<'de> Deserialize<'de> for HideConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
const PATTERN: &str = "pattern";
const BEGIN: &str = "begin";
const END: &str = "end";

use serde::de::Error;

struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = HideConfig;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
formatter,
"a map with the field `pattern`, or a map with the fields `start` and an optional `end`"
f,
"a map with wither the field `{PATTERN}`, or the fields `{BEGIN}` and optionally `{END}`"
)
}

fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let unexpected = |k| A::Error::custom(format!("unexpected field `{k}`"));
let (k1, v1) = map
.next_entry::<String, String>()?
.ok_or_else(|| A::Error::custom("missing field `pattern` or `start`"))?;

match &*k1 {
"pattern" => {
if let Some(k2) = map.next_key::<String>()? {
return Err(unexpected(k2));
}
Ok(HideConfig::Pattern { pattern: v1 })
}
"begin" => {
let Some((k2, v2)) = map.next_entry::<String, String>()? else {
return Ok(HideConfig::Span {
begin: v1,
end: None,
});
};
(k2 == "end")
.then(|| HideConfig::Span {
begin: v1,
end: Some(v2),
})
.ok_or_else(|| unexpected(k2))
}
"end" => {
let (k2, v2) = map
.next_entry::<String, String>()?
.ok_or_else(|| A::Error::missing_field("begin"))?;
(k2 == "begin")
.then(|| HideConfig::Span {
begin: v2,
end: Some(v1),
})
.ok_or_else(|| unexpected(k2))
}
_ => Err(unexpected(k1)),
let mut entries = HashMap::<String, String>::default();
while let Some((k, v)) = map.next_entry::<String, String>()? {
entries.insert(k, v);
}

if entries.contains_key(PATTERN) && entries.contains_key(BEGIN) {
return Err(Error::custom(format!(
"cannot use `{PATTERN}` and `{BEGIN}` toghether"
)));
}
if let Some(pattern) = entries.remove(PATTERN) {
Ok(HideConfig::Pattern { pattern })
} else if let Some(begin) = entries.remove(BEGIN) {
let end = entries.remove(END);
Ok(HideConfig::Span { begin, end })
} else {
Err(Error::custom(format!(
"missing field `{PATTERN}` or `{BEGIN}`"
)))
}
}
}
Expand Down

0 comments on commit d3b48db

Please sign in to comment.