Skip to content

Commit

Permalink
refactor: Use more serde_untagged
Browse files Browse the repository at this point in the history
  • Loading branch information
epage committed Aug 28, 2023
1 parent 17c4431 commit a27b68b
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 156 deletions.
197 changes: 43 additions & 154 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1171,195 +1171,84 @@ type MaybeWorkspaceSemverVersion = MaybeWorkspace<semver::Version, TomlWorkspace

type MaybeWorkspaceString = MaybeWorkspace<String, TomlWorkspaceField>;
impl<'de> de::Deserialize<'de> for MaybeWorkspaceString {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;

impl<'de> de::Visitor<'de> for Visitor {
type Value = MaybeWorkspaceString;

fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.write_str("a string or workspace")
}

fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(MaybeWorkspaceString::Defined(value))
}

fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
let mvd = de::value::MapAccessDeserializer::new(map);
TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
}
}

d.deserialize_any(Visitor)
UntaggedEnumVisitor::new()
.expecting("a string or workspace")
.string(|value| Ok(MaybeWorkspace::Defined(value.to_owned())))
.map(|value| value.deserialize().map(MaybeWorkspace::Workspace))
.deserialize(deserializer)
}
}

type MaybeWorkspacePartialVersion = MaybeWorkspace<PartialVersion, TomlWorkspaceField>;
impl<'de> de::Deserialize<'de> for MaybeWorkspacePartialVersion {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;

impl<'de> de::Visitor<'de> for Visitor {
type Value = MaybeWorkspacePartialVersion;

fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.write_str("a semver or workspace")
}

fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: de::Error,
{
let value = value.parse::<PartialVersion>().map_err(|e| E::custom(e))?;
Ok(MaybeWorkspacePartialVersion::Defined(value))
}

fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
let mvd = de::value::MapAccessDeserializer::new(map);
TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
}
}

d.deserialize_any(Visitor)
use serde::de::Error as _;
UntaggedEnumVisitor::new()
.expecting("a SemVer version or workspace")
.string(|value| {
let value = value
.parse::<PartialVersion>()
.map_err(|e| serde_untagged::de::Error::custom(e))?;
Ok(MaybeWorkspace::Defined(value))
})
.map(|value| value.deserialize().map(MaybeWorkspace::Workspace))
.deserialize(deserializer)
}
}

type MaybeWorkspaceVecString = MaybeWorkspace<Vec<String>, TomlWorkspaceField>;
impl<'de> de::Deserialize<'de> for MaybeWorkspaceVecString {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;

impl<'de> de::Visitor<'de> for Visitor {
type Value = MaybeWorkspaceVecString;

fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("a vector of strings or workspace")
}
fn visit_seq<A>(self, v: A) -> Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
let seq = de::value::SeqAccessDeserializer::new(v);
Vec::deserialize(seq).map(MaybeWorkspace::Defined)
}

fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
let mvd = de::value::MapAccessDeserializer::new(map);
TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
}
}

d.deserialize_any(Visitor)
UntaggedEnumVisitor::new()
.expecting("a vector of strings or workspace")
.seq(|value| value.deserialize().map(MaybeWorkspace::Defined))
.map(|value| value.deserialize().map(MaybeWorkspace::Workspace))
.deserialize(deserializer)
}
}

type MaybeWorkspaceStringOrBool = MaybeWorkspace<StringOrBool, TomlWorkspaceField>;
impl<'de> de::Deserialize<'de> for MaybeWorkspaceStringOrBool {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;

impl<'de> de::Visitor<'de> for Visitor {
type Value = MaybeWorkspaceStringOrBool;

fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("a string, a bool, or workspace")
}

fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: de::Error,
{
let b = de::value::BoolDeserializer::new(v);
StringOrBool::deserialize(b).map(MaybeWorkspace::Defined)
}

fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: de::Error,
{
let string = de::value::StringDeserializer::new(v);
StringOrBool::deserialize(string).map(MaybeWorkspace::Defined)
}

fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
let mvd = de::value::MapAccessDeserializer::new(map);
TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
}
}

d.deserialize_any(Visitor)
UntaggedEnumVisitor::new()
.expecting("a string, a bool, or workspace")
.bool(|b| Ok(StringOrBool::Bool(b)).map(MaybeWorkspace::Defined))
.string(|s| Ok(StringOrBool::String(s.to_owned())).map(MaybeWorkspace::Defined))
.map(|value| value.deserialize().map(MaybeWorkspace::Workspace))
.deserialize(deserializer)
}
}

type MaybeWorkspaceVecStringOrBool = MaybeWorkspace<VecStringOrBool, TomlWorkspaceField>;
impl<'de> de::Deserialize<'de> for MaybeWorkspaceVecStringOrBool {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;

impl<'de> de::Visitor<'de> for Visitor {
type Value = MaybeWorkspaceVecStringOrBool;

fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("a boolean, a vector of strings, or workspace")
}

fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: de::Error,
{
let b = de::value::BoolDeserializer::new(v);
VecStringOrBool::deserialize(b).map(MaybeWorkspace::Defined)
}

fn visit_seq<A>(self, v: A) -> Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
let seq = de::value::SeqAccessDeserializer::new(v);
VecStringOrBool::deserialize(seq).map(MaybeWorkspace::Defined)
}

fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
let mvd = de::value::MapAccessDeserializer::new(map);
TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
}
}

d.deserialize_any(Visitor)
UntaggedEnumVisitor::new()
.expecting("a boolean, a vector of strings, or workspace")
.bool(|value| Ok(VecStringOrBool::Bool(value)).map(MaybeWorkspace::Defined))
.seq(|value| {
value
.deserialize()
.map(VecStringOrBool::VecString)
.map(MaybeWorkspace::Defined)
})
.map(|value| value.deserialize().map(MaybeWorkspace::Workspace))
.deserialize(deserializer)
}
}

Expand Down
6 changes: 4 additions & 2 deletions tests/testsuite/inheritable_workspace_fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1234,11 +1234,13 @@ fn error_workspace_false() {
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
TOML parse error at line 7, column 41
TOML parse error at line 7, column 27
|
7 | description = { workspace = false }
| ^^^^^
| ^^^^^^^^^^^^^^^^^^^^^
`workspace` cannot be false
in `workspace`
",
)
.run();
Expand Down

0 comments on commit a27b68b

Please sign in to comment.