diff --git a/.travis.yml b/.travis.yml index 729796b5..ea9e7fe8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ script: - (cd testing && travis-cargo --skip nightly test) - (cd testing && travis-cargo --only nightly test -- --features unstable-testing) - (cd serde_derive && travis-cargo --only nightly test) +- (cd serde_derive/no-std-tests && travis-cargo --only nightly build) #- (cd examples/serde-syntex-example && travis-cargo --skip nightly run) #- (cd examples/serde-syntex-example && travis-cargo --only nightly run -- --no-default-features --features unstable) - (cd serde && travis-cargo --only stable doc) diff --git a/serde/src/export.rs b/serde/src/export.rs new file mode 100644 index 00000000..61c9ba67 --- /dev/null +++ b/serde/src/export.rs @@ -0,0 +1,33 @@ +#[cfg(all(feature = "collections", not(feature = "std")))] +use collections::String; + +#[cfg(feature = "std")] +use std::borrow::Cow; +#[cfg(all(feature = "collections", not(feature = "std")))] +use collections::borrow::Cow; + +pub use core::default::Default; +pub use core::fmt; +pub use core::marker::PhantomData; +pub use core::result::Result; + +#[cfg(any(feature = "collections", feature = "std"))] +pub fn from_utf8_lossy(bytes: &[u8]) -> Cow { + String::from_utf8_lossy(bytes) +} + +// The generated code calls this like: +// +// let value = &_serde::export::from_utf8_lossy(bytes); +// Err(_serde::de::Error::unknown_variant(value, VARIANTS)) +// +// so it is okay for the return type to be different from the std case as long +// as the above works. +#[cfg(not(any(feature = "collections", feature = "std")))] +pub fn from_utf8_lossy(bytes: &[u8]) -> &str { + use core::str; + // Three unicode replacement characters if it fails. They look like a + // white-on-black question mark. The user will recognize it as invalid + // UTF-8. + str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}") +} diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 093fa286..77a04932 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -31,7 +31,7 @@ extern crate core as actual_core; #[cfg(feature = "std")] mod core { pub use std::{ops, hash, fmt, cmp, marker, mem, i8, i16, i32, i64, u8, u16, u32, u64, isize, - usize, f32, f64, char, str, num, slice, iter, cell}; + usize, f32, f64, char, str, num, slice, iter, cell, default, result}; #[cfg(feature = "unstable")] pub use actual_core::nonzero; } @@ -50,3 +50,7 @@ pub mod ser; #[cfg_attr(feature = "std", doc(hidden))] pub mod error; mod utils; + +// Generated code uses these to support no_std. Not public API. +#[doc(hidden)] +pub mod export; diff --git a/serde_codegen/src/de.rs b/serde_codegen/src/de.rs index eda81859..65f4905c 100644 --- a/serde_codegen/src/de.rs +++ b/serde_codegen/src/de.rs @@ -36,7 +36,7 @@ pub fn expand_derive_deserialize(item: &syn::MacroInput) -> Result(deserializer: __D) -> ::std::result::Result<#ty, __D::Error> + fn deserialize<__D>(deserializer: __D) -> _serde::export::Result<#ty, __D::Error> where __D: _serde::Deserializer #body } @@ -158,11 +158,11 @@ fn deserialize_visitor(generics: &syn::Generics) -> (Tokens, Tokens, Tokens) { let phantom_types = generics.lifetimes.iter() .map(|lifetime_def| { let lifetime = &lifetime_def.lifetime; - quote!(::std::marker::PhantomData<& #lifetime ()>) + quote!(_serde::export::PhantomData<& #lifetime ()>) }).chain(generics.ty_params.iter() .map(|ty_param| { let ident = &ty_param.ident; - quote!(::std::marker::PhantomData<#ident>) + quote!(_serde::export::PhantomData<#ident>) })); let all_params = generics.lifetimes.iter() @@ -182,7 +182,7 @@ fn deserialize_visitor(generics: &syn::Generics) -> (Tokens, Tokens, Tokens) { Some(quote!(::<#(#ty_param_idents),*>)) }; - let phantom_exprs = iter::repeat(quote!(::std::marker::PhantomData)).take(num_phantoms); + let phantom_exprs = iter::repeat(quote!(_serde::export::PhantomData)).take(num_phantoms); ( quote! { @@ -208,19 +208,19 @@ fn deserialize_unit_struct( impl _serde::de::Visitor for __Visitor { type Value = #type_ident; - fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn expecting(&self, formatter: &mut _serde::export::fmt::Formatter) -> _serde::export::fmt::Result { formatter.write_str(#expecting) } #[inline] - fn visit_unit<__E>(self) -> ::std::result::Result<#type_ident, __E> + fn visit_unit<__E>(self) -> _serde::export::Result<#type_ident, __E> where __E: _serde::de::Error, { Ok(#type_ident) } #[inline] - fn visit_seq<__V>(self, _: __V) -> ::std::result::Result<#type_ident, __V::Error> + fn visit_seq<__V>(self, _: __V) -> _serde::export::Result<#type_ident, __V::Error> where __V: _serde::de::SeqVisitor, { Ok(#type_ident) @@ -297,14 +297,14 @@ fn deserialize_tuple( impl #impl_generics _serde::de::Visitor for #visitor_ty #where_clause { type Value = #ty; - fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn expecting(&self, formatter: &mut _serde::export::fmt::Formatter) -> _serde::export::fmt::Result { formatter.write_str(#expecting) } #visit_newtype_struct #[inline] - fn visit_seq<__V>(self, #visitor_var: __V) -> ::std::result::Result<#ty, __V::Error> + fn visit_seq<__V>(self, #visitor_var: __V) -> _serde::export::Result<#ty, __V::Error> where __V: _serde::de::SeqVisitor { #visit_seq @@ -408,7 +408,7 @@ fn deserialize_newtype_struct( }; quote! { #[inline] - fn visit_newtype_struct<__E>(self, __e: __E) -> ::std::result::Result + fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result where __E: _serde::Deserializer, { Ok(#type_path(#value)) @@ -480,19 +480,19 @@ fn deserialize_struct( impl #impl_generics _serde::de::Visitor for #visitor_ty #where_clause { type Value = #ty; - fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn expecting(&self, formatter: &mut _serde::export::fmt::Formatter) -> _serde::export::fmt::Result { formatter.write_str(#expecting) } #[inline] - fn visit_seq<__V>(self, #visitor_var: __V) -> ::std::result::Result<#ty, __V::Error> + fn visit_seq<__V>(self, #visitor_var: __V) -> _serde::export::Result<#ty, __V::Error> where __V: _serde::de::SeqVisitor { #visit_seq } #[inline] - fn visit_map<__V>(self, mut visitor: __V) -> ::std::result::Result<#ty, __V::Error> + fn visit_map<__V>(self, mut visitor: __V) -> _serde::export::Result<#ty, __V::Error> where __V: _serde::de::MapVisitor { #visit_map @@ -585,11 +585,11 @@ fn deserialize_item_enum( impl #impl_generics _serde::de::Visitor for #visitor_ty #where_clause { type Value = #ty; - fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn expecting(&self, formatter: &mut _serde::export::fmt::Formatter) -> _serde::export::fmt::Result { formatter.write_str(#expecting) } - fn visit_enum<__V>(self, visitor: __V) -> ::std::result::Result<#ty, __V::Error> + fn visit_enum<__V>(self, visitor: __V) -> _serde::export::Result<#ty, __V::Error> where __V: _serde::de::EnumVisitor, { #match_variant @@ -696,7 +696,7 @@ fn deserialize_field_visitor( let variant_indices = 0usize..; let fallthrough_msg = format!("variant index 0 <= i < {}", fields.len()); Some(quote! { - fn visit_usize<__E>(self, value: usize) -> ::std::result::Result<__Field, __E> + fn visit_usize<__E>(self, value: usize) -> _serde::export::Result<__Field, __E> where __E: _serde::de::Error { match value { @@ -731,7 +731,7 @@ fn deserialize_field_visitor( Some(quote! { // TODO https://github.com/serde-rs/serde/issues/666 // update this to use str::from_utf8(value).unwrap_or("���") on no_std - let value = &::std::string::String::from_utf8_lossy(value); + let value = &_serde::export::from_utf8_lossy(value); }) } else { None @@ -746,7 +746,7 @@ fn deserialize_field_visitor( impl _serde::Deserialize for __Field { #[inline] - fn deserialize<__D>(deserializer: __D) -> ::std::result::Result<__Field, __D::Error> + fn deserialize<__D>(deserializer: __D) -> _serde::export::Result<__Field, __D::Error> where __D: _serde::Deserializer, { struct __FieldVisitor; @@ -754,13 +754,13 @@ fn deserialize_field_visitor( impl _serde::de::Visitor for __FieldVisitor { type Value = __Field; - fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn expecting(&self, formatter: &mut _serde::export::fmt::Formatter) -> _serde::export::fmt::Result { formatter.write_str("field name") } #visit_usize - fn visit_str<__E>(self, value: &str) -> ::std::result::Result<__Field, __E> + fn visit_str<__E>(self, value: &str) -> _serde::export::Result<__Field, __E> where __E: _serde::de::Error { match value { @@ -771,7 +771,7 @@ fn deserialize_field_visitor( } } - fn visit_bytes<__E>(self, value: &[u8]) -> ::std::result::Result<__Field, __E> + fn visit_bytes<__E>(self, value: &[u8]) -> _serde::export::Result<__Field, __E> where __E: _serde::de::Error { match value { @@ -981,18 +981,18 @@ fn wrap_deserialize_with( quote! { struct __SerdeDeserializeWithStruct #impl_generics #where_clause { value: #field_ty, - phantom: ::std::marker::PhantomData<#phantom_ty>, + phantom: _serde::export::PhantomData<#phantom_ty>, } }, quote! { impl #impl_generics _serde::Deserialize for #wrapper_ty #where_clause { - fn deserialize<__D>(__d: __D) -> ::std::result::Result + fn deserialize<__D>(__d: __D) -> _serde::export::Result where __D: _serde::Deserializer { let value = try!(#deserialize_with(__d)); Ok(__SerdeDeserializeWithStruct { value: value, - phantom: ::std::marker::PhantomData, + phantom: _serde::export::PhantomData, }) } } @@ -1004,7 +1004,7 @@ fn wrap_deserialize_with( fn expr_is_missing(attrs: &attr::Field) -> Tokens { match *attrs.default() { attr::FieldDefault::Default => { - return quote!(::std::default::Default::default()); + return quote!(_serde::export::Default::default()); } attr::FieldDefault::Path(ref path) => { return quote!(#path()); diff --git a/serde_codegen/src/ser.rs b/serde_codegen/src/ser.rs index 3374d5ac..ae3a6c7f 100644 --- a/serde_codegen/src/ser.rs +++ b/serde_codegen/src/ser.rs @@ -30,7 +30,7 @@ pub fn expand_derive_serialize(item: &syn::MacroInput) -> Result extern crate serde as _serde; #[automatically_derived] impl #impl_generics _serde::Serialize for #ty #where_clause { - fn serialize<__S>(&self, _serializer: __S) -> ::std::result::Result<__S::Ok, __S::Error> + fn serialize<__S>(&self, _serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> where __S: _serde::Serializer { #body @@ -541,7 +541,7 @@ fn wrap_serialize_with( } impl #wrapper_generics _serde::Serialize for #wrapper_ty #where_clause { - fn serialize<__S>(&self, __s: __S) -> ::std::result::Result<__S::Ok, __S::Error> + fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error> where __S: _serde::Serializer { #path(self.value, __s) diff --git a/serde_derive/no-std-tests/Cargo.toml b/serde_derive/no-std-tests/Cargo.toml new file mode 100644 index 00000000..432a962c --- /dev/null +++ b/serde_derive/no-std-tests/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "serde_derive_tests_no_std" +version = "0.9.0-rc2" +publish = false + +[dependencies] +serde = { path = "../../serde", default-features = false } +serde_derive = { path = ".." } diff --git a/serde_derive/no-std-tests/src/main.rs b/serde_derive/no-std-tests/src/main.rs new file mode 100644 index 00000000..5eae5267 --- /dev/null +++ b/serde_derive/no-std-tests/src/main.rs @@ -0,0 +1,50 @@ +#![feature(lang_items, start, libc)] +#![no_std] + +extern crate libc; + +#[start] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} + +#[lang = "eh_personality"] +#[no_mangle] +pub extern fn rust_eh_personality() {} + +#[lang = "eh_unwind_resume"] +#[no_mangle] +pub extern fn rust_eh_unwind_resume() {} + +#[lang = "panic_fmt"] +#[no_mangle] +pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, + _file: &'static str, + _line: u32) -> ! { + loop {} +} + +////////////////////////////////////////////////////////////////////////////// + +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize, Deserialize)] +struct Unit; + +#[derive(Serialize, Deserialize)] +struct Newtype(u8); + +#[derive(Serialize, Deserialize)] +struct Tuple(u8, u8); + +#[derive(Serialize, Deserialize)] +struct Struct { f: u8 } + +#[derive(Serialize, Deserialize)] +enum Enum { + Unit, + Newtype(u8), + Tuple(u8, u8), + Struct { f: u8 }, +}