Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ jobs:
env:
MIRIFLAGS: -Zmiri-strict-provenance

no_std:
name: No default features (no_std)
needs: pre_ci
if: needs.pre_ci.outputs.continue
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo check --no-default-features

minimal:
name: Minimal versions
needs: pre_ci
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.cache/
/target/
/Cargo.lock
rust_out
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ license = "MIT OR Apache-2.0"
repository = "https://github.com/yaml/yaml-serde"
rust-version = "1.82"

[features]
default = ["std"]
std = ["serde/std", "indexmap/std"]

Comment thread
pawelchcki marked this conversation as resolved.
[dependencies]
indexmap = "2.2.1"
indexmap = { version = "2.2.1", default-features = false }
itoa = "1.0"
ryu = "1.0"
serde = "1.0.195"
serde = { version = "1.0.195", default-features = false, features = ["alloc"] }
libyaml-rs = "0.3"

[dev-dependencies]
Expand Down
30 changes: 19 additions & 11 deletions src/de.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#[cfg(feature = "std")]
use alloc::boxed::Box;
use alloc::sync::Arc;
use alloc::{format, vec::Vec};
use crate::error::{self, Error, ErrorImpl};
use crate::libyaml::error::Mark;
use crate::libyaml::parser::{MappingStart, Scalar, ScalarStyle, SequenceStart};
Expand All @@ -6,16 +10,17 @@ use crate::loader::{Document, Loader};
use crate::path::Path;
use serde::de::value::StrDeserializer;
use serde::de::{
self, Deserialize, DeserializeOwned, DeserializeSeed, Expected, IgnoredAny, Unexpected, Visitor,
self, Deserialize, DeserializeSeed, Expected, IgnoredAny, Unexpected, Visitor,
};
use std::fmt;
use std::io;
use std::mem;
use std::num::ParseIntError;
use std::str;
use std::sync::Arc;
use core::fmt;
use core::mem;
use core::num::ParseIntError;
use core::str;

type Result<T, E = Error> = std::result::Result<T, E>;
#[cfg(feature = "std")]
use serde::de::DeserializeOwned;

type Result<T, E = Error> = core::result::Result<T, E>;

/// A structure that deserializes YAML into Rust values.
///
Expand Down Expand Up @@ -62,7 +67,8 @@ pub struct Deserializer<'de> {
pub(crate) enum Progress<'de> {
Str(&'de str),
Slice(&'de [u8]),
Read(Box<dyn io::Read + 'de>),
#[cfg(feature = "std")]
Read(Box<dyn crate::io::Read + 'de>),
Iterable(Loader<'de>),
Document(Document<'de>),
Fail(Arc<ErrorImpl>),
Expand All @@ -86,9 +92,10 @@ impl<'de> Deserializer<'de> {
/// Reader-based deserializers do not support deserializing borrowed types
/// like `&str`, since the `std::io::Read` trait has no non-copying methods
/// -- everything it does involves copying bytes out of the data source.
#[cfg(feature = "std")]
pub fn from_reader<R>(rdr: R) -> Self
where
R: io::Read + 'de,
R: crate::io::Read + 'de,
{
let progress = Progress::Read(Box::new(rdr));
Deserializer { progress }
Expand Down Expand Up @@ -1817,9 +1824,10 @@ where
/// is wrong with the data, for example required struct fields are missing from
/// the YAML map or some number is too big to fit in the expected primitive
/// type.
#[cfg(feature = "std")]
pub fn from_reader<R, T>(rdr: R) -> Result<T>
where
R: io::Read,
R: crate::io::Read,
T: DeserializeOwned,
{
T::deserialize(Deserializer::from_reader(rdr))
Expand Down
15 changes: 8 additions & 7 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use alloc::sync::Arc;
use crate::io;
use crate::libyaml::{emitter, error as libyaml};
use crate::path::Path;
use core::error::Error as StdError;
use core::fmt::{self, Debug, Display};
use core::result;
use serde::{de, ser};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;
use std::string;
use std::sync::Arc;

/// An error that happened serializing or deserializing YAML data.
pub struct Error(Box<ErrorImpl>);
Expand All @@ -20,7 +21,7 @@ pub(crate) enum ErrorImpl {

Libyaml(libyaml::Error),
Io(io::Error),
FromUtf8(string::FromUtf8Error),
FromUtf8(alloc::string::FromUtf8Error),

EndOfStream,
MoreThanOneDocument,
Expand Down
97 changes: 97 additions & 0 deletions src/io.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//! I/O traits abstracted over std and no_std.
//!
//! In std mode, re-exports from `std::io`.
//! In no_std mode, provides a minimal `Write` trait and error type.
//!
//! This follows the same pattern as `serde_json`:
//! <https://github.com/serde-rs/json/blob/master/src/io/mod.rs>

#[cfg(feature = "std")]
pub use std::io::{Error, Read, Write};

#[cfg(feature = "std")]
pub(crate) fn sink() -> std::io::Sink {
std::io::sink()
}

#[cfg(not(feature = "std"))]
pub use self::nostd::{Error, Write};

#[cfg(not(feature = "std"))]
pub(crate) use self::nostd::sink;

#[cfg(not(feature = "std"))]
mod nostd {
use alloc::vec::Vec;
use core::fmt;

pub type Result<T> = core::result::Result<T, Error>;

/// I/O error type for no_std mode.
pub struct Error;

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("I/O error")
}
}

impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("io::Error")
}
}

impl core::error::Error for Error {}
Comment thread
pawelchcki marked this conversation as resolved.

/// Minimal `Write` trait for no_std environments.
pub trait Write {
/// Write all bytes from `buf` into the writer.
fn write_all(&mut self, buf: &[u8]) -> Result<()>;
/// Flush buffered data.
fn flush(&mut self) -> Result<()>;
}

impl<W: Write + ?Sized> Write for &mut W {
#[inline]
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
(**self).write_all(buf)
}

#[inline]
fn flush(&mut self) -> Result<()> {
(**self).flush()
}
}

pub fn sink() -> Sink {
Sink
}

pub struct Sink;

impl Write for Sink {
#[inline]
fn write_all(&mut self, _buf: &[u8]) -> Result<()> {
Ok(())
}

#[inline]
fn flush(&mut self) -> Result<()> {
Ok(())
}
}

impl Write for Vec<u8> {
#[inline]
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
self.extend_from_slice(buf);
Ok(())
}

#[inline]
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
}
12 changes: 11 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
//! }
//! ```

#![no_std]
#![doc(html_root_url = "https://docs.rs/yaml_serde/0.10.4")]
#![deny(missing_docs, unsafe_op_in_unsafe_fn)]
// Suppressed clippy_pedantic lints
Expand Down Expand Up @@ -164,7 +165,14 @@
clippy::must_use_candidate,
)]

pub use crate::de::{from_reader, from_slice, from_str, Deserializer};
#[cfg(feature = "std")]
extern crate std;

extern crate alloc;

#[cfg(feature = "std")]
pub use crate::de::from_reader;
pub use crate::de::{from_slice, from_str, Deserializer};
pub use crate::error::{Error, Location, Result};
pub use crate::ser::{to_string, to_writer, Serializer};
#[doc(inline)]
Expand All @@ -175,6 +183,7 @@ pub use crate::mapping::Mapping;

mod de;
mod error;
pub mod io;
mod libyaml;
mod loader;
pub mod mapping;
Expand All @@ -186,6 +195,7 @@ pub mod with;

// Prevent downstream code from implementing the Index trait.
mod private {
use alloc::string::String;
pub trait Sealed {}
impl Sealed for usize {}
impl Sealed for str {}
Expand Down
10 changes: 5 additions & 5 deletions src/libyaml/cstr.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::fmt::{self, Debug, Display, Write as _};
use std::marker::PhantomData;
use std::ptr::NonNull;
use std::slice;
use std::str;
use core::fmt::{self, Debug, Display, Write as _};
use core::marker::PhantomData;
use core::ptr::NonNull;
use core::slice;
use core::str;

#[derive(Copy, Clone)]
pub(crate) struct CStr<'a> {
Expand Down
15 changes: 9 additions & 6 deletions src/libyaml/emitter.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use alloc::boxed::Box;
use alloc::string::String;
use crate::io;
use crate::libyaml;
use crate::libyaml::util::Owned;
use std::ffi::c_void;
use std::io;
use std::mem::{self, MaybeUninit};
use std::ptr::{self, addr_of_mut};
use std::slice;
use core::ffi::c_void;
use core::mem::{self, MaybeUninit};
use core::ptr::{self, addr_of_mut};
use core::slice;
use libyaml_rs as sys;

#[derive(Debug)]
Expand Down Expand Up @@ -181,7 +183,7 @@ impl<'a> Emitter<'a> {
}

pub fn into_inner(self) -> Box<dyn io::Write + 'a> {
let sink = Box::new(io::sink());
let sink: Box<dyn io::Write> = Box::new(io::sink());
unsafe { mem::replace(&mut (*self.pin.ptr).write, sink) }
}

Expand Down Expand Up @@ -210,6 +212,7 @@ unsafe fn write_handler(data: *mut c_void, buffer: *mut u8, size: u64) -> i32 {
}
}


impl Drop for EmitterPinned<'_> {
fn drop(&mut self) {
unsafe { sys::yaml_emitter_delete(&raw mut self.sys) }
Expand Down
8 changes: 4 additions & 4 deletions src/libyaml/error.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::libyaml::cstr::CStr;
use std::fmt::{self, Debug, Display};
use std::mem::MaybeUninit;
use std::ptr::NonNull;
use core::fmt::{self, Debug, Display};
use core::mem::MaybeUninit;
use core::ptr::NonNull;
use libyaml_rs as sys;

pub(crate) type Result<T> = std::result::Result<T, Error>;
pub(crate) type Result<T> = core::result::Result<T, Error>;

pub(crate) struct Error {
kind: sys::yaml_error_type_t,
Expand Down
11 changes: 6 additions & 5 deletions src/libyaml/parser.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use alloc::borrow::Cow;
use alloc::boxed::Box;
use crate::libyaml::cstr::{self, CStr};
use crate::libyaml::error::{Error, Mark, Result};
use crate::libyaml::tag::Tag;
use crate::libyaml::util::Owned;
use std::borrow::Cow;
use std::fmt::{self, Debug};
use std::mem::MaybeUninit;
use std::ptr::{addr_of_mut, NonNull};
use std::slice;
use core::fmt::{self, Debug};
use core::mem::MaybeUninit;
use core::ptr::{addr_of_mut, NonNull};
use core::slice;
use libyaml_rs as sys;

pub(crate) struct Parser<'input> {
Expand Down
5 changes: 3 additions & 2 deletions src/libyaml/tag.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use alloc::boxed::Box;
use crate::libyaml::cstr;
use std::fmt::{self, Debug};
use std::ops::Deref;
use core::fmt::{self, Debug};
use core::ops::Deref;

#[derive(Ord, PartialOrd, Eq, PartialEq)]
pub(crate) struct Tag(pub(in crate::libyaml) Box<[u8]>);
Expand Down
9 changes: 5 additions & 4 deletions src/libyaml/util.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::marker::PhantomData;
use std::mem::{self, MaybeUninit};
use std::ops::Deref;
use std::ptr::{addr_of, NonNull};
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::mem::{self, MaybeUninit};
use core::ops::Deref;
use core::ptr::{addr_of, NonNull};

pub(crate) struct Owned<T, Init = T> {
ptr: NonNull<T>,
Expand Down
Loading