Skip to content

Commit ba7fe7f

Browse files
authored
feat(toml)!: Add no_std compatibility (#952)
This gets us `alloc` but not `core`. For `core`, see `toml_parse` / `toml_write` Closes #904 Fixes #360
2 parents 3ec8dbc + 5daa18d commit ba7fe7f

36 files changed

+206
-122
lines changed

crates/serde_spanned/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,13 @@ pre-release-replacements = [
2323
{file="CHANGELOG.md", search="<!-- next-url -->", replace="<!-- next-url -->\n[Unreleased]: https://github.com/toml-rs/toml/compare/{{tag_name}}...HEAD", exactly=1},
2424
]
2525

26+
[features]
27+
default = ["std"]
28+
alloc = []
29+
std = ["alloc"]
30+
2631
[dependencies]
27-
serde = { version = "1.0.145", optional = true }
32+
serde = { version = "1.0.145", optional = true, default-features = false }
2833

2934
[dev-dependencies]
3035
serde = "1"

crates/serde_spanned/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
//! [serde]: https://serde.rs/
77
88
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
9+
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
910
#![warn(missing_docs)]
11+
#![warn(clippy::std_instead_of_core)]
12+
#![warn(clippy::std_instead_of_alloc)]
1013
// Makes rustc abort compilation if there are any unsafe blocks in the crate.
1114
// Presence of this annotation is picked up by tools such as cargo-geiger
1215
// and lets them ensure that there is indeed no unsafe code as opposed to
@@ -15,6 +18,10 @@
1518
#![warn(clippy::print_stderr)]
1619
#![warn(clippy::print_stdout)]
1720

21+
#[cfg(feature = "alloc")]
22+
#[allow(unused_extern_crates)]
23+
extern crate alloc;
24+
1825
mod spanned;
1926
pub use crate::spanned::Spanned;
2027

crates/serde_spanned/src/spanned.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use std::cmp::Ordering;
2-
use std::hash::{Hash, Hasher};
1+
use core::cmp::Ordering;
2+
use core::hash::{Hash, Hasher};
33

44
// Currently serde itself doesn't have a spanned type, so we map our `Spanned`
55
// to a special value in the serde data model. Namely one with these special
@@ -29,7 +29,7 @@ pub fn is_spanned(name: &'static str, fields: &'static [&'static str]) -> bool {
2929
#[derive(Clone, Debug)]
3030
pub struct Spanned<T> {
3131
/// Byte range
32-
span: std::ops::Range<usize>,
32+
span: core::ops::Range<usize>,
3333
/// The spanned value.
3434
value: T,
3535
}
@@ -88,12 +88,12 @@ impl<T> Spanned<T> {
8888
/// #
8989
/// # type DetailedDependency = std::collections::BTreeMap<String, String>;
9090
/// ```
91-
pub fn new(range: std::ops::Range<usize>, value: T) -> Self {
91+
pub fn new(range: core::ops::Range<usize>, value: T) -> Self {
9292
Spanned { span: range, value }
9393
}
9494

9595
/// Byte range
96-
pub fn span(&self) -> std::ops::Range<usize> {
96+
pub fn span(&self) -> core::ops::Range<usize> {
9797
self.span.clone()
9898
}
9999

@@ -113,19 +113,22 @@ impl<T> Spanned<T> {
113113
}
114114
}
115115

116-
impl<T: std::fmt::Display> std::fmt::Display for Spanned<T> {
117-
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116+
impl<T: core::fmt::Display> core::fmt::Display for Spanned<T> {
117+
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118118
self.get_ref().fmt(fmt)
119119
}
120120
}
121121

122-
impl std::borrow::Borrow<str> for Spanned<String> {
122+
#[cfg(feature = "alloc")]
123+
#[allow(unused_qualifications)]
124+
impl core::borrow::Borrow<str> for Spanned<alloc::string::String> {
123125
fn borrow(&self) -> &str {
124126
self.get_ref()
125127
}
126128
}
127129

128-
impl std::borrow::Borrow<str> for Spanned<std::borrow::Cow<'_, str>> {
130+
#[cfg(feature = "alloc")]
131+
impl core::borrow::Borrow<str> for Spanned<alloc::borrow::Cow<'_, str>> {
129132
fn borrow(&self) -> &str {
130133
self.get_ref()
131134
}
@@ -178,15 +181,15 @@ where
178181
where
179182
D: serde::de::Deserializer<'de>,
180183
{
181-
struct SpannedVisitor<T>(::std::marker::PhantomData<T>);
184+
struct SpannedVisitor<T>(::core::marker::PhantomData<T>);
182185

183186
impl<'de, T> serde::de::Visitor<'de> for SpannedVisitor<T>
184187
where
185188
T: serde::de::Deserialize<'de>,
186189
{
187190
type Value = Spanned<T>;
188191

189-
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192+
fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
190193
formatter.write_str("a spanned value")
191194
}
192195

@@ -239,7 +242,7 @@ where
239242

240243
static FIELDS: [&str; 3] = [START_FIELD, END_FIELD, VALUE_FIELD];
241244

242-
let visitor = SpannedVisitor(::std::marker::PhantomData);
245+
let visitor = SpannedVisitor(::core::marker::PhantomData);
243246

244247
deserializer.deserialize_struct(NAME, &FIELDS, visitor)
245248
}

crates/serde_spanned/tests/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::cmp::{Ord, Ordering, PartialOrd};
1+
use core::cmp::{Ord, Ordering, PartialOrd};
22

33
use serde_spanned::Spanned;
44

crates/toml/Cargo.toml

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ implementations of the standard Serialize/Deserialize traits for TOML data to
77
facilitate deserializing and serializing Rust structures.
88
"""
99
categories = ["encoding", "parser-implementations", "parsing", "config"]
10-
keywords = ["encoding", "toml"]
10+
keywords = ["encoding", "toml", "no_std"]
1111
repository.workspace = true
1212
license.workspace = true
1313
edition.workspace = true
@@ -29,10 +29,11 @@ pre-release-replacements = [
2929

3030
[features]
3131
default = ["parse", "display"]
32+
std = ["indexmap?/std"]
3233
parse = ["dep:toml_parse", "dep:winnow"]
33-
display = ["dep:toml_edit", "toml_edit?/display"]
34+
display = ["std", "dep:toml_edit", "toml_edit?/display"]
3435
unsafe = ["toml_parse?/unsafe"]
35-
debug = ["toml_parse?/debug", "dep:anstream", "dep:anstyle"]
36+
debug = ["std", "toml_parse?/debug", "dep:anstream", "dep:anstyle"]
3637

3738
# Provide a method disable_recursion_limit to parse arbitrarily deep structures
3839
# without any consideration for overflowing the stack. Additionally you will
@@ -44,18 +45,18 @@ unbounded = []
4445
# Use indexmap rather than BTreeMap as the map type of toml::Value.
4546
# This allows data to be read into a Value and written back to a TOML string
4647
# while preserving the order of map keys in the input.
47-
preserve_order = ["dep:indexmap"]
48+
preserve_order = ["dep:indexmap", "std"]
4849

4950
[dependencies]
50-
serde = "1.0.145"
51-
indexmap = { version = "2.0.0", optional = true }
52-
toml_parse = { version = "0.1.0", path = "../toml_parse", optional = true }
53-
winnow = { version = "0.7.10", optional = true }
51+
serde = { version = "1.0.145", default-features = false, features = ["alloc"] }
52+
indexmap = { version = "2.0.0", default-features = false, optional = true }
53+
toml_parse = { version = "0.1.0", path = "../toml_parse", default-features = false, features = ["alloc"], optional = true }
54+
winnow = { version = "0.7.10", default-features = false, optional = true }
5455
anstream = { version = "0.6.15", optional = true }
5556
anstyle = { version = "1.0.8", optional = true }
5657
toml_edit = { version = "0.22.27", path = "../toml_edit", default-features = false, features = ["serde"], optional = true }
57-
toml_datetime = { version = "0.6.11", path = "../toml_datetime", features = ["serde"] }
58-
serde_spanned = { version = "0.6.9", path = "../serde_spanned", features = ["serde"] }
58+
toml_datetime = { version = "0.6.11", path = "../toml_datetime", default-features = false, features = ["serde", "alloc"] }
59+
serde_spanned = { version = "0.6.9", path = "../serde_spanned", default-features = false, features = ["serde", "alloc"] }
5960

6061
[dev-dependencies]
6162
serde = { version = "1.0.199", features = ["derive"] }

crates/toml/src/de/array.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use crate::de::Error;
66

77
pub(crate) struct ArrayDeserializer<'i> {
88
input: DeArray<'i>,
9-
span: Option<std::ops::Range<usize>>,
9+
span: Option<core::ops::Range<usize>>,
1010
}
1111

1212
impl<'i> ArrayDeserializer<'i> {
13-
pub(crate) fn new(input: DeArray<'i>, span: Option<std::ops::Range<usize>>) -> Self {
13+
pub(crate) fn new(input: DeArray<'i>, span: Option<core::ops::Range<usize>>) -> Self {
1414
Self { input, span }
1515
}
1616
}
@@ -59,7 +59,7 @@ impl<'de> serde::de::IntoDeserializer<'de, Error> for ArrayDeserializer<'de> {
5959
}
6060

6161
pub(crate) struct ArraySeqAccess<'i> {
62-
iter: std::vec::IntoIter<Spanned<DeValue<'i>>>,
62+
iter: alloc::vec::IntoIter<Spanned<DeValue<'i>>>,
6363
}
6464

6565
impl<'i> ArraySeqAccess<'i> {

crates/toml/src/de/datetime.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use serde::de::value::BorrowedStrDeserializer;
22
use serde::de::IntoDeserializer;
33

4+
use crate::alloc_prelude::*;
45
use crate::de::Error;
56

67
pub(crate) struct DatetimeDeserializer {

crates/toml/src/de/dearray.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use serde_spanned::Spanned;
22

3+
use crate::alloc_prelude::*;
34
use crate::de::DeValue;
45

56
/// Type representing a TOML array, payload of the `DeValue::Array` variant
@@ -40,7 +41,7 @@ impl DeArray<'_> {
4041
}
4142
}
4243

43-
impl<'i> std::ops::Deref for DeArray<'i> {
44+
impl<'i> core::ops::Deref for DeArray<'i> {
4445
type Target = [Spanned<DeValue<'i>>];
4546

4647
#[inline]
@@ -49,7 +50,7 @@ impl<'i> std::ops::Deref for DeArray<'i> {
4950
}
5051
}
5152

52-
impl<'i> std::ops::DerefMut for DeArray<'i> {
53+
impl<'i> core::ops::DerefMut for DeArray<'i> {
5354
#[inline]
5455
fn deref_mut(&mut self) -> &mut [Spanned<DeValue<'i>>] {
5556
self.items.as_mut_slice()
@@ -68,19 +69,19 @@ impl<'i> AsMut<[Spanned<DeValue<'i>>]> for DeArray<'i> {
6869
}
6970
}
7071

71-
impl<'i> std::borrow::Borrow<[Spanned<DeValue<'i>>]> for DeArray<'i> {
72+
impl<'i> core::borrow::Borrow<[Spanned<DeValue<'i>>]> for DeArray<'i> {
7273
fn borrow(&self) -> &[Spanned<DeValue<'i>>] {
7374
&self.items[..]
7475
}
7576
}
7677

77-
impl<'i> std::borrow::BorrowMut<[Spanned<DeValue<'i>>]> for DeArray<'i> {
78+
impl<'i> core::borrow::BorrowMut<[Spanned<DeValue<'i>>]> for DeArray<'i> {
7879
fn borrow_mut(&mut self) -> &mut [Spanned<DeValue<'i>>] {
7980
&mut self.items[..]
8081
}
8182
}
8283

83-
impl<'i, I: std::slice::SliceIndex<[Spanned<DeValue<'i>>]>> std::ops::Index<I> for DeArray<'i> {
84+
impl<'i, I: core::slice::SliceIndex<[Spanned<DeValue<'i>>]>> core::ops::Index<I> for DeArray<'i> {
8485
type Output = I::Output;
8586

8687
#[inline]
@@ -92,7 +93,7 @@ impl<'i, I: std::slice::SliceIndex<[Spanned<DeValue<'i>>]>> std::ops::Index<I> f
9293
impl<'a, 'i> IntoIterator for &'a DeArray<'i> {
9394
type Item = &'a Spanned<DeValue<'i>>;
9495

95-
type IntoIter = std::slice::Iter<'a, Spanned<DeValue<'i>>>;
96+
type IntoIter = core::slice::Iter<'a, Spanned<DeValue<'i>>>;
9697

9798
fn into_iter(self) -> Self::IntoIter {
9899
self.iter()
@@ -102,7 +103,7 @@ impl<'a, 'i> IntoIterator for &'a DeArray<'i> {
102103
impl<'i> IntoIterator for DeArray<'i> {
103104
type Item = Spanned<DeValue<'i>>;
104105

105-
type IntoIter = std::vec::IntoIter<Spanned<DeValue<'i>>>;
106+
type IntoIter = alloc::vec::IntoIter<Spanned<DeValue<'i>>>;
106107

107108
#[inline]
108109
fn into_iter(self) -> Self::IntoIter {
@@ -140,9 +141,9 @@ impl PartialEq for DeArray<'_> {
140141

141142
impl Eq for DeArray<'_> {}
142143

143-
impl std::fmt::Debug for DeArray<'_> {
144+
impl core::fmt::Debug for DeArray<'_> {
144145
#[inline]
145-
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146+
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
146147
self.items.fmt(formatter)
147148
}
148149
}

crates/toml/src/de/detable.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::borrow::Cow;
1+
use alloc::borrow::Cow;
22

33
use serde_spanned::Spanned;
44

@@ -29,7 +29,7 @@ impl<'i> DeTable<'i> {
2929

3030
/// Ensure no data is borrowed
3131
pub fn make_owned(&mut self) {
32-
let borrowed = std::mem::take(self);
32+
let borrowed = core::mem::take(self);
3333
let owned = borrowed
3434
.into_iter()
3535
.map(|(k, mut v)| {

crates/toml/src/de/devalue.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
//! Definition of a TOML [value][DeValue] for deserialization
22
3-
use std::borrow::Cow;
4-
use std::mem::discriminant;
5-
use std::ops;
3+
use alloc::borrow::Cow;
4+
use core::mem::discriminant;
5+
use core::ops;
66

77
use serde_spanned::Spanned;
88
use toml_datetime::Datetime;
99

10+
use crate::alloc_prelude::*;
1011
use crate::de::DeArray;
1112
use crate::de::DeTable;
1213

@@ -49,7 +50,7 @@ impl<'i> DeValue<'i> {
4950
pub fn make_owned(&mut self) {
5051
match self {
5152
DeValue::String(v) => {
52-
let owned = std::mem::take(v);
53+
let owned = core::mem::take(v);
5354
*v = Cow::Owned(owned.into_owned());
5455
}
5556
DeValue::Integer(..)

0 commit comments

Comments
 (0)