Skip to content

Commit 529cfc3

Browse files
committed
Remove toml as a public dependency
This removes toml as a public dependency. This reduces the exposure of the public API, reduces exposure of internal implementation, and makes it easier to make semver-incompatible changes to toml. This is accomplished through a variety of changes: - `get` and `get_mut` are removed. - `get_deserialized_opt` is renamed to `get`. - Dropped the AsRef for `get_deserialized_opt` for ergonomics, since using an `&` for a String is not too much to ask, and the other generic arg needs to be specified in a fair number of situations. - Removed deprecated `get_deserialized`. - Dropped `TomlExt` from the public API. - Removed `get_renderer` and `get_preprocessor` since they were trivial wrappers over `get`.
1 parent 8053774 commit 529cfc3

File tree

10 files changed

+161
-238
lines changed

10 files changed

+161
-238
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/mdbook-core/src/config.rs

Lines changed: 41 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,32 @@
2424
//! [build]
2525
//! src = "out"
2626
//!
27-
//! [other-table.foo]
27+
//! [preprocessor.my-preprocessor]
2828
//! bar = 123
2929
//! "#;
3030
//!
3131
//! // load the `Config` from a toml string
3232
//! let mut cfg = Config::from_str(src)?;
3333
//!
3434
//! // retrieve a nested value
35-
//! let bar = cfg.get("other-table.foo.bar").cloned();
36-
//! assert_eq!(bar, Some(Value::Integer(123)));
35+
//! let bar = cfg.get::<i32>("preprocessor.my-preprocessor.bar")?;
36+
//! assert_eq!(bar, Some(123));
3737
//!
3838
//! // Set the `output.html.theme` directory
39-
//! assert!(cfg.get("output.html").is_none());
39+
//! assert!(cfg.get::<Value>("output.html")?.is_none());
4040
//! cfg.set("output.html.theme", "./themes");
4141
//!
4242
//! // then load it again, automatically deserializing to a `PathBuf`.
43-
//! let got: Option<PathBuf> = cfg.get_deserialized_opt("output.html.theme")?;
43+
//! let got = cfg.get("output.html.theme")?;
4444
//! assert_eq!(got, Some(PathBuf::from("./themes")));
4545
//! # Ok(())
4646
//! # }
4747
//! # run().unwrap()
4848
//! ```
4949
50+
use crate::utils::TomlExt;
5051
use crate::utils::log_backtrace;
51-
use crate::utils::toml_ext::TomlExt;
52-
use anyhow::{Context, Error, Result, bail};
52+
use anyhow::{Context, Error, Result};
5353
use log::{debug, trace, warn};
5454
use serde::{Deserialize, Deserializer, Serialize, Serializer};
5555
use std::collections::HashMap;
@@ -154,18 +154,28 @@ impl Config {
154154
}
155155
}
156156

157-
/// Fetch an arbitrary item from the `Config` as a `toml::Value`.
157+
/// Get a value from the configuration.
158158
///
159-
/// You can use dotted indices to access nested items (e.g.
160-
/// `output.html.playground` will fetch the "playground" out of the html output
161-
/// table).
162-
pub fn get(&self, key: &str) -> Option<&Value> {
163-
self.rest.read(key)
164-
}
165-
166-
/// Fetch a value from the `Config` so you can mutate it.
167-
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
168-
self.rest.read_mut(key)
159+
/// This fetches a value from the book configuration. The key can have
160+
/// dotted indices to access nested items (e.g. `output.html.playground`
161+
/// will fetch the "playground" out of the html output table).
162+
///
163+
/// This does not have access to the [`Config::book`], [`Config::build`],
164+
/// or [`Config::rust`] fields.
165+
///
166+
/// Returns `Ok(None)` if the field is not set.
167+
///
168+
/// Returns `Err` if it fails to deserialize.
169+
pub fn get<'de, T: Deserialize<'de>>(&self, name: &str) -> Result<Option<T>> {
170+
self.rest
171+
.read(name)
172+
.map(|value| {
173+
value
174+
.clone()
175+
.try_into()
176+
.with_context(|| "Couldn't deserialize the value")
177+
})
178+
.transpose()
169179
}
170180

171181
/// Convenience method for getting the html renderer's configuration.
@@ -177,7 +187,7 @@ impl Config {
177187
#[doc(hidden)]
178188
pub fn html_config(&self) -> Option<HtmlConfig> {
179189
match self
180-
.get_deserialized_opt("output.html")
190+
.get("output.html")
181191
.with_context(|| "Parsing configuration [output.html]")
182192
{
183193
Ok(Some(config)) => Some(config),
@@ -189,35 +199,12 @@ impl Config {
189199
}
190200
}
191201

192-
/// Deprecated, use get_deserialized_opt instead.
193-
#[deprecated = "use get_deserialized_opt instead"]
194-
pub fn get_deserialized<'de, T: Deserialize<'de>, S: AsRef<str>>(&self, name: S) -> Result<T> {
195-
let name = name.as_ref();
196-
match self.get_deserialized_opt(name)? {
197-
Some(value) => Ok(value),
198-
None => bail!("Key not found, {:?}", name),
199-
}
200-
}
201-
202-
/// Convenience function to fetch a value from the config and deserialize it
203-
/// into some arbitrary type.
204-
pub fn get_deserialized_opt<'de, T: Deserialize<'de>, S: AsRef<str>>(
205-
&self,
206-
name: S,
207-
) -> Result<Option<T>> {
208-
let name = name.as_ref();
209-
self.get(name)
210-
.map(|value| {
211-
value
212-
.clone()
213-
.try_into()
214-
.with_context(|| "Couldn't deserialize the value")
215-
})
216-
.transpose()
217-
}
218-
219202
/// Set a config key, clobbering any existing values along the way.
220203
///
204+
/// The key can have dotted indices for nested items (e.g.
205+
/// `output.html.playground` will set the "playground" in the html output
206+
/// table).
207+
///
221208
/// The only way this can fail is if we can't serialize `value` into a
222209
/// `toml::Value`.
223210
pub fn set<S: Serialize, I: AsRef<str>>(&mut self, index: I, value: S) -> Result<()> {
@@ -239,18 +226,6 @@ impl Config {
239226
Ok(())
240227
}
241228

242-
/// Get the table associated with a particular renderer.
243-
pub fn get_renderer<I: AsRef<str>>(&self, index: I) -> Option<&Table> {
244-
let key = format!("output.{}", index.as_ref());
245-
self.get(&key).and_then(Value::as_table)
246-
}
247-
248-
/// Get the table associated with a particular preprocessor.
249-
pub fn get_preprocessor<I: AsRef<str>>(&self, index: I) -> Option<&Table> {
250-
let key = format!("preprocessor.{}", index.as_ref());
251-
self.get(&key).and_then(Value::as_table)
252-
}
253-
254229
fn from_legacy(mut table: Value) -> Config {
255230
let mut cfg = Config::default();
256231

@@ -1021,32 +996,16 @@ mod tests {
1021996
};
1022997

1023998
let cfg = Config::from_str(src).unwrap();
1024-
let got: RandomOutput = cfg.get_deserialized_opt("output.random").unwrap().unwrap();
999+
let got: RandomOutput = cfg.get("output.random").unwrap().unwrap();
10251000

10261001
assert_eq!(got, should_be);
10271002

1028-
let got_baz: Vec<bool> = cfg
1029-
.get_deserialized_opt("output.random.baz")
1030-
.unwrap()
1031-
.unwrap();
1003+
let got_baz: Vec<bool> = cfg.get("output.random.baz").unwrap().unwrap();
10321004
let baz_should_be = vec![true, true, false];
10331005

10341006
assert_eq!(got_baz, baz_should_be);
10351007
}
10361008

1037-
#[test]
1038-
fn mutate_some_stuff() {
1039-
// really this is just a sanity check to make sure the borrow checker
1040-
// is happy...
1041-
let src = COMPLEX_CONFIG;
1042-
let mut config = Config::from_str(src).unwrap();
1043-
let key = "output.html.playground.editable";
1044-
1045-
assert_eq!(config.get(key).unwrap(), &Value::Boolean(true));
1046-
*config.get_mut(key).unwrap() = Value::Boolean(false);
1047-
assert_eq!(config.get(key).unwrap(), &Value::Boolean(false));
1048-
}
1049-
10501009
/// The config file format has slightly changed (metadata stuff is now under
10511010
/// the `book` table instead of being at the top level) so we're adding a
10521011
/// **temporary** compatibility check. You should be able to still load the
@@ -1106,10 +1065,10 @@ mod tests {
11061065
let key = "foo.bar.baz";
11071066
let value = "Something Interesting";
11081067

1109-
assert!(cfg.get(key).is_none());
1068+
assert!(cfg.get::<i32>(key).unwrap().is_none());
11101069
cfg.set(key, value).unwrap();
11111070

1112-
let got: String = cfg.get_deserialized_opt(key).unwrap().unwrap();
1071+
let got: String = cfg.get(key).unwrap().unwrap();
11131072
assert_eq!(got, value);
11141073
}
11151074

@@ -1159,18 +1118,15 @@ mod tests {
11591118
let key = "foo.bar";
11601119
let value = "baz";
11611120

1162-
assert!(cfg.get(key).is_none());
1121+
assert!(cfg.get::<String>(key).unwrap().is_none());
11631122

11641123
let encoded_key = encode_env_var(key);
11651124
// TODO: This is unsafe, and should be rewritten to use a process.
11661125
unsafe { env::set_var(encoded_key, value) };
11671126

11681127
cfg.update_from_env();
11691128

1170-
assert_eq!(
1171-
cfg.get_deserialized_opt::<String, _>(key).unwrap().unwrap(),
1172-
value
1173-
);
1129+
assert_eq!(cfg.get::<String>(key).unwrap().unwrap(), value);
11741130
}
11751131

11761132
#[test]
@@ -1180,20 +1136,15 @@ mod tests {
11801136
let value = json!({"array": [1, 2, 3], "number": 13.37});
11811137
let value_str = serde_json::to_string(&value).unwrap();
11821138

1183-
assert!(cfg.get(key).is_none());
1139+
assert!(cfg.get::<serde_json::Value>(key).unwrap().is_none());
11841140

11851141
let encoded_key = encode_env_var(key);
11861142
// TODO: This is unsafe, and should be rewritten to use a process.
11871143
unsafe { env::set_var(encoded_key, value_str) };
11881144

11891145
cfg.update_from_env();
11901146

1191-
assert_eq!(
1192-
cfg.get_deserialized_opt::<serde_json::Value, _>(key)
1193-
.unwrap()
1194-
.unwrap(),
1195-
value
1196-
);
1147+
assert_eq!(cfg.get::<serde_json::Value>(key).unwrap().unwrap(), value);
11971148
}
11981149

11991150
#[test]

crates/mdbook-core/src/utils/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use std::sync::LazyLock;
99

1010
pub mod fs;
1111
mod string;
12-
pub mod toml_ext;
12+
mod toml_ext;
13+
14+
pub(crate) use self::toml_ext::TomlExt;
1315

1416
pub use self::string::{
1517
take_anchored_lines, take_lines, take_rustdoc_include_anchored_lines,

crates/mdbook-core/src/utils/toml_ext.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
use toml::value::{Table, Value};
44

55
/// Helper for working with toml types.
6-
pub trait TomlExt {
6+
pub(crate) trait TomlExt {
77
/// Read a dotted key.
88
fn read(&self, key: &str) -> Option<&Value>;
9-
/// Read a dotted key for a mutable value.
10-
fn read_mut(&mut self, key: &str) -> Option<&mut Value>;
119
/// Insert with a dotted key.
1210
fn insert(&mut self, key: &str, value: Value);
1311
/// Delete a dotted key value.
@@ -23,14 +21,6 @@ impl TomlExt for Value {
2321
}
2422
}
2523

26-
fn read_mut(&mut self, key: &str) -> Option<&mut Value> {
27-
if let Some((head, tail)) = split(key) {
28-
self.get_mut(head)?.read_mut(tail)
29-
} else {
30-
self.get_mut(key)
31-
}
32-
}
33-
3424
fn insert(&mut self, key: &str, value: Value) {
3525
if !self.is_table() {
3626
*self = Value::Table(Table::new());

crates/mdbook-driver/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mdbook-preprocessor.workspace = true
1717
mdbook-renderer.workspace = true
1818
mdbook-summary.workspace = true
1919
regex.workspace = true
20+
serde.workspace = true
2021
serde_json.workspace = true
2122
shlex.workspace = true
2223
tempfile.workspace = true

crates/mdbook-driver/src/builtin_renderers/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use std::fs;
1010
use std::io::{self, ErrorKind};
1111
use std::path::{Path, PathBuf};
1212
use std::process::{Command, Stdio};
13-
use toml::Value;
1413

1514
pub use self::markdown_renderer::MarkdownRenderer;
1615

@@ -108,8 +107,9 @@ impl CmdRenderer {
108107
let optional_key = format!("output.{}.optional", self.name);
109108

110109
let is_optional = match ctx.config.get(&optional_key) {
111-
Some(Value::Boolean(value)) => *value,
112-
_ => false,
110+
Ok(Some(value)) => value,
111+
Err(e) => bail!("expected bool for `{optional_key}`: {e}"),
112+
Ok(None) => false,
113113
};
114114

115115
if is_optional {

0 commit comments

Comments
 (0)