Skip to content

Commit

Permalink
Handle discontiguous TOML table entries
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Mar 16, 2024
1 parent 835f9da commit 02970ac
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 2 deletions.
5 changes: 3 additions & 2 deletions src/dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::directory::Directory;
use crate::error::Error;
use crate::inherit::InheritEdition;
use crate::manifest::Edition;
use crate::toml;
use serde::de::value::MapAccessDeserializer;
use serde::de::value::StrDeserializer;
use serde::de::{self, Deserialize, Deserializer, Visitor};
Expand All @@ -17,7 +18,7 @@ pub(crate) fn get_manifest(manifest_dir: &Directory) -> Result<Manifest, Error>
let cargo_toml_path = manifest_dir.join("Cargo.toml");
let mut manifest = (|| {
let manifest_str = fs::read_to_string(&cargo_toml_path)?;
let manifest: Manifest = basic_toml::from_str(&manifest_str)?;
let manifest: Manifest = toml::from_str(&manifest_str)?;
Ok(manifest)
})()
.map_err(|err| Error::GetManifest(cargo_toml_path, Box::new(err)))?;
Expand All @@ -41,7 +42,7 @@ pub(crate) fn try_get_workspace_manifest(
) -> Result<WorkspaceManifest, Error> {
let cargo_toml_path = manifest_dir.join("Cargo.toml");
let manifest_str = fs::read_to_string(cargo_toml_path)?;
let mut manifest: WorkspaceManifest = basic_toml::from_str(&manifest_str)?;
let mut manifest: WorkspaceManifest = toml::from_str(&manifest_str)?;

fix_dependencies(&mut manifest.workspace.dependencies, manifest_dir);
fix_patches(&mut manifest.patch, manifest_dir);
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ mod message;
mod normalize;
mod run;
mod rustflags;
mod toml;

use std::cell::RefCell;
use std::panic::RefUnwindSafe;
Expand Down
113 changes: 113 additions & 0 deletions src/toml.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use basic_toml::Error;
use serde::de::{Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
use serde_json::map::{Entry, Map};
use serde_json::{Number, Value};
use std::fmt;

pub(crate) fn from_str<T>(document: &str) -> Result<T, Error>
where
T: for<'de> Deserialize<'de>,
{
let result = basic_toml::from_str::<T>(document);
let error = match result {
Ok(value) => return Ok(value),
Err(error) => error,
};

let result = basic_toml::from_str::<Toml>(document);
if let Ok(toml) = result {
if let Ok(value) = T::deserialize(toml.0) {
return Ok(value);
}
}

Err(error)
}

struct Toml(Value);

impl<'de> Deserialize<'de> for Toml {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(TomlVisitor).map(Toml)
}
}

struct TomlVisitor;

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

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("any valid TOML value")
}

fn visit_bool<E>(self, value: bool) -> Result<Value, E> {
Ok(Value::Bool(value))
}

fn visit_i64<E>(self, value: i64) -> Result<Value, E> {
Ok(Value::Number(value.into()))
}

fn visit_f64<E>(self, value: f64) -> Result<Value, E> {
Ok(Number::from_f64(value).map_or(Value::Null, Value::Number))
}

fn visit_str<E>(self, value: &str) -> Result<Value, E>
where
E: serde::de::Error,
{
self.visit_string(String::from(value))
}

fn visit_string<E>(self, value: String) -> Result<Value, E> {
Ok(Value::String(value))
}

fn visit_seq<V>(self, mut visitor: V) -> Result<Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut vec = Vec::new();

while let Some(elem) = visitor.next_element()? {
vec.push(elem);
}

Ok(Value::Array(vec))
}

fn visit_map<V>(self, mut visitor: V) -> Result<Value, V::Error>
where
V: MapAccess<'de>,
{
let mut values = Map::new();

while let Some((key, value)) = visitor.next_entry::<String, Value>()? {
match values.entry(key) {
Entry::Vacant(entry) => {
entry.insert(value);
}
Entry::Occupied(mut entry) => {
merge(entry.get_mut(), value);
}
}
}

Ok(Value::Object(values))
}
}

fn merge(a: &mut Value, b: Value) {
match (a, b) {
(Value::Object(a), Value::Object(b)) => {
for (k, v) in b {
merge(a.entry(k).or_insert(Value::Null), v);
}
}
(a, b) => *a = b,
}
}

0 comments on commit 02970ac

Please sign in to comment.