Skip to content

Commit

Permalink
Use serde instead of writing it out by hand
Browse files Browse the repository at this point in the history
As a side benefit, this has much less copying.
  • Loading branch information
jyn514 committed Aug 24, 2020
1 parent 7b15aff commit b5475ca
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 56 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions metadata/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ description = "Document crates the same way docs.rs would"
path = "lib.rs"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
toml = { version = "0.5", default-features = false }
thiserror = "1"
85 changes: 29 additions & 56 deletions metadata/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use std::process::Command;
//! use metadata::Metadata;
//! use docsrs_metadata::Metadata;
//!
//! // First, we need to parse Cargo.toml.
//! let source_root = env!("CARGO_MANIFEST_DIR");
Expand Down Expand Up @@ -36,8 +36,9 @@ use std::collections::{HashMap, HashSet};
use std::io;
use std::path::Path;

use serde::Deserialize;
use thiserror::Error;
use toml::{map::Map, Value};
use toml::Value;

/// The target that `metadata` is being built for.
///
Expand Down Expand Up @@ -91,19 +92,23 @@ pub enum MetadataError {
/// ```
///
/// You can define one or more fields in your `Cargo.toml`.
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Metadata {
/// List of features to pass on to `cargo`.
///
/// By default, docs.rs will only build default features.
pub features: Option<Vec<String>>,

/// Whether to pass `--all-features` to `cargo`.
#[serde(default)]
pub all_features: bool,

/// Whether to pass `--no-default-features` to `cargo`.
//
/// By default, Docs.rs will build default features.
/// Set `no-default-fatures` to `false` if you want to build only certain features.
/// Set `no-default-fatures` to `true` if you want to build only certain features.
#[serde(default)]
pub no_default_features: bool,

/// See [`BuildTargets`].
Expand Down Expand Up @@ -251,63 +256,31 @@ impl std::str::FromStr for Metadata {

/// Parse the given manifest as TOML.
fn from_str(manifest: &str) -> Result<Metadata, Self::Err> {
let mut metadata = Metadata::default();
use toml::value::Table;

let manifest = manifest.parse::<Value>()?;

fn fetch_manifest_tables<'a>(manifest: &'a Value) -> Option<&'a Map<String, Value>> {
manifest
.get("package")?
.as_table()?
.get("metadata")?
.as_table()?
.get("docs")?
.as_table()?
.get("rs")?
.as_table()
}
let manifest = match manifest.parse::<Value>()? {
Value::Table(t) => Some(t),
_ => None,
};

if let Some(table) = fetch_manifest_tables(&manifest) {
// TODO: all this `to_owned` is inefficient, this should use explicit matches instead.
let collect_into_array =
|f: &Vec<Value>| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect();

metadata.features = table
.get("features")
.and_then(|f| f.as_array())
.and_then(collect_into_array);

metadata.no_default_features = table
.get("no-default-features")
.and_then(|v| v.as_bool())
.unwrap_or(metadata.no_default_features);

metadata.all_features = table
.get("all-features")
.and_then(|v| v.as_bool())
.unwrap_or(metadata.all_features);

metadata.default_target = table
.get("default-target")
.and_then(|v| v.as_str())
.map(|v| v.to_owned());

metadata.targets = table
.get("targets")
.and_then(|f| f.as_array())
.and_then(collect_into_array);

metadata.rustc_args = table
.get("rustc-args")
.and_then(|f| f.as_array())
.and_then(collect_into_array);

metadata.rustdoc_args = table
.get("rustdoc-args")
.and_then(|f| f.as_array())
.and_then(collect_into_array);
fn table<'a>(mut manifest: Table, table_name: &str) -> Option<Table> {
match manifest.remove(table_name) {
Some(Value::Table(table)) => Some(table),
_ => None,
}
}

let table = manifest
.and_then(|t| table(t, "package"))
.and_then(|t| table(t, "metadata"))
.and_then(|t| table(t, "docs"))
.and_then(|t| table(t, "rs"));
let metadata = if let Some(table) = table {
Value::Table(table).try_into()?
} else {
Metadata::default()
};

Ok(metadata)
}
}
Expand Down

0 comments on commit b5475ca

Please sign in to comment.