Skip to content

Commit

Permalink
Merge pull request #158 from jpopesculian/no_std
Browse files Browse the repository at this point in the history
Add no_std support
  • Loading branch information
tafia authored May 17, 2020
2 parents d452c6c + e78a173 commit 5325627
Show file tree
Hide file tree
Showing 23 changed files with 504 additions and 2,278 deletions.
7 changes: 7 additions & 0 deletions generate_modules.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,17 @@ proto_sets=(
quick-protobuf/tests/rust_protobuf/common
)

nostd_proto_sets=(
quick-protobuf/examples/pb_rs_nostd
)

for ps in "${proto_sets[@]}"; do
cargo run -p pb-rs -- -I "$ps" -d "$ps" "$ps"/*.proto
done

for ps in "${nostd_proto_sets[@]}"; do
cargo run -p pb-rs -- --nostd -I "$ps" -d "$ps" "$ps"/*.proto
done

rm -rf quick-protobuf/examples/pb_rs_v3/owned
mkdir -p quick-protobuf/examples/pb_rs_v3/owned
Expand Down
17 changes: 17 additions & 0 deletions pb-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ pub struct ConfigBuilder {
custom_struct_derive: Vec<String>,
custom_repr: Option<String>,
owned: bool,
nostd: bool,
hashbrown: bool,
}

impl ConfigBuilder {
Expand Down Expand Up @@ -169,6 +171,19 @@ impl ConfigBuilder {
self
}

/// Generate no_std compliant code
pub fn nostd(mut self, val: bool) -> Self {
self.nostd = val;
self
}

/// Use hashbrown as HashMap implementation instead of [std::collections::HashMap] or
/// [alloc::collections::BTreeMap] in a `no_std` environment
pub fn hashbrown(mut self, val: bool) -> Self {
self.hashbrown = val;
self
}

/// Build Config from this ConfigBuilder
pub fn build(self) -> Vec<Config> {
self.in_files
Expand Down Expand Up @@ -198,6 +213,8 @@ impl ConfigBuilder {
custom_rpc_generator: Box::new(|_, _| Ok(())),
custom_includes: Vec::new(),
owned: self.owned,
nostd: self.nostd,
hashbrown: self.hashbrown,
}
})
.collect()
Expand Down
12 changes: 12 additions & 0 deletions pb-rs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ fn run() -> Result<(), ::failure::Error> {
.long("owned")
.required(false)
.help("Generate Owned structs when the proto stuct has a lifetime"),
).arg(
Arg::with_name("NOSTD")
.long("nostd")
.required(false)
.help("Generate no_std compliant code"),
).arg(
Arg::with_name("HASHBROWN")
.long("hashrown")
.required(false)
.help("Use hashrown for HashMap implementation"),
).get_matches();

let in_files = path_vec(values_t!(matches, "INPUT", String));
Expand All @@ -113,6 +123,8 @@ fn run() -> Result<(), ::failure::Error> {
.headers(!matches.is_present("NO_HEADERS"))
.dont_use_cow(matches.is_present("DONT_USE_COW"))
.custom_struct_derive(custom_struct_derive)
.nostd(matches.is_present("NOSTD"))
.hashbrown(matches.is_present("HASHBROWN"))
.custom_repr(custom_repr)
.owned(matches.is_present("OWNED"));

Expand Down
119 changes: 85 additions & 34 deletions pb-rs/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ impl FieldType {
format!("{}{}{}", m.get_modules(desc), m.name, lifetime)
}
FieldType::Map(ref key, ref value) => format!(
"HashMap<{}, {}>",
"KVMap<{}, {}>",
key.rust_type(desc)?,
value.rust_type(desc)?
),
Expand Down Expand Up @@ -449,15 +449,15 @@ impl Field {
"i32" => format!("{}i32", *d),
"i64" => format!("{}i64", *d),
"f32" => match &*d.to_lowercase() {
"inf" => "::std::f32::INFINITY".to_string(),
"-inf" => "::std::f32::NEG_INFINITY".to_string(),
"nan" => "::std::f32::NAN".to_string(),
"inf" => "::core::f32::INFINITY".to_string(),
"-inf" => "::core::f32::NEG_INFINITY".to_string(),
"nan" => "::core::f32::NAN".to_string(),
_ => format!("{}f32", *d),
},
"f64" => match &*d.to_lowercase() {
"inf" => "::std::f64::INFINITY".to_string(),
"-inf" => "::std::f64::NEG_INFINITY".to_string(),
"nan" => "::std::f64::NAN".to_string(),
"inf" => "::core::f64::INFINITY".to_string(),
"-inf" => "::core::f64::NEG_INFINITY".to_string(),
"nan" => "::core::f64::NAN".to_string(),
_ => format!("{}f64", *d),
},
"Cow<'a, str>" => format!("Cow::Borrowed({})", d),
Expand Down Expand Up @@ -849,19 +849,43 @@ impl Message {
writeln!(w)?;
writeln!(w, "pub mod mod_{} {{", self.name)?;
writeln!(w)?;
if self
.messages
.iter()
.any(|m| m.all_fields().any(|f| f.typ.has_cow()))
if config.nostd {
writeln!(w, "use alloc::vec::Vec;")?;
}
if self.messages.iter().any(|m| {
m.all_fields()
.any(|f| (f.typ.has_cow() || (f.packed() && f.typ.is_fixed_size())))
}) {
if config.nostd {
writeln!(w, "use alloc::borrow::Cow;")?;
} else {
writeln!(w, "use std::borrow::Cow;")?;
}
}
if config.nostd
&& self.messages.iter().any(|m| {
desc.owned && m.has_lifetime(desc, &mut Vec::new())
|| m.all_fields().any(|f| f.boxed)
})
{
writeln!(w, "use std::borrow::Cow;")?;
writeln!(w)?;
writeln!(w, "use alloc::boxed::Box;")?;
}
if self
.messages
.iter()
.any(|m| m.all_fields().any(|f| f.typ.is_map()))
{
writeln!(w, "use std::collections::HashMap;")?;
if config.hashbrown {
writeln!(w, "use hashbrown::HashMap;")?;
writeln!(w, "type KVMap<K, V> = HashMap<K, V>;")?;
} else if config.nostd {
writeln!(w, "use alloc::collections::BTreeMap;")?;
writeln!(w, "type KVMap<K, V> = BTreeMap<K, V>;")?;
} else {
writeln!(w, "use std::collections::HashMap;")?;
writeln!(w, "type KVMap<K, V> = HashMap<K, V>;")?;
}
}
if !self.messages.is_empty() || !self.oneofs.is_empty() {
writeln!(w, "use super::*;")?;
Expand Down Expand Up @@ -1045,31 +1069,31 @@ impl Message {
struct {name}OwnedInner {{
buf: Vec<u8>,
proto: {name}<'static>,
_pin: std::marker::PhantomPinned,
_pin: core::marker::PhantomPinned,
}}
impl {name}OwnedInner {{
fn new(buf: Vec<u8>) -> Result<std::pin::Pin<Box<Self>>> {{
fn new(buf: Vec<u8>) -> Result<core::pin::Pin<Box<Self>>> {{
let inner = Self {{
buf,
proto: unsafe {{ std::mem::MaybeUninit::zeroed().assume_init() }},
_pin: std::marker::PhantomPinned,
proto: unsafe {{ core::mem::MaybeUninit::zeroed().assume_init() }},
_pin: core::marker::PhantomPinned,
}};
let mut pinned = Box::pin(inner);
let mut reader = BytesReader::from_bytes(&pinned.buf);
let proto = {name}::from_reader(&mut reader, &pinned.buf)?;
unsafe {{
let proto = std::mem::transmute::<_, {name}<'static>>(proto);
let proto = core::mem::transmute::<_, {name}<'static>>(proto);
pinned.as_mut().get_unchecked_mut().proto = proto;
}}
Ok(pinned)
}}
}}
pub struct {name}Owned {{
inner: std::pin::Pin<Box<{name}OwnedInner>>,
inner: core::pin::Pin<Box<{name}OwnedInner>>,
}}
#[allow(dead_code)]
Expand All @@ -1083,8 +1107,8 @@ impl Message {
}}
}}
impl std::fmt::Debug for {name}Owned {{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {{
impl core::fmt::Debug for {name}Owned {{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {{
self.inner.proto.fmt(f)
}}
}}
Expand Down Expand Up @@ -1123,7 +1147,7 @@ impl Message {
}}
}}
"#,
name = self.name
name = self.name,
)?;
Ok(())
}
Expand All @@ -1144,7 +1168,7 @@ impl Message {
fn write_write_message<W: Write>(&self, w: &mut W, desc: &FileDescriptor) -> Result<()> {
writeln!(
w,
" fn write_message<W: Write>(&self, w: &mut Writer<W>) -> Result<()> {{"
" fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {{"
)?;
for f in self.fields.iter().filter(|f| !f.deprecated) {
f.write_write(w, desc)?;
Expand Down Expand Up @@ -1658,6 +1682,8 @@ pub struct Config {
pub custom_rpc_generator: RpcGeneratorFunction,
pub custom_includes: Vec<String>,
pub owned: bool,
pub nostd: bool,
pub hashbrown: bool,
}

#[derive(Debug, Default, Clone)]
Expand Down Expand Up @@ -2153,33 +2179,58 @@ impl FileDescriptor {
)?;
return Ok(());
}
writeln!(w, "use std::io::Write;")?;
if self
.messages
.iter()
.any(|m| m.all_fields().any(|f| f.typ.has_cow()))

if config.nostd {
writeln!(w, "use alloc::vec::Vec;")?;
}

if self.messages.iter().any(|m| {
m.all_fields()
.any(|f| (f.typ.has_cow() || (f.packed() && f.typ.is_fixed_size())))
}) {
if config.nostd {
writeln!(w, "use alloc::borrow::Cow;")?;
} else {
writeln!(w, "use std::borrow::Cow;")?;
}
}
if config.nostd
&& self.messages.iter().any(|m| {
self.owned && m.has_lifetime(&self, &mut Vec::new())
|| m.all_fields().any(|f| f.boxed)
})
{
writeln!(w, "use std::borrow::Cow;")?;
writeln!(w)?;
writeln!(w, "use alloc::boxed::Box;")?;
}
if self
.messages
.iter()
.any(|m| m.all_fields().any(|f| f.typ.is_map()))
{
writeln!(w, "use std::collections::HashMap;")?;
if config.hashbrown {
writeln!(w, "use hashbrown::HashMap;")?;
writeln!(w, "type KVMap<K, V> = HashMap<K, V>;")?;
} else if config.nostd {
writeln!(w, "use alloc::collections::BTreeMap;")?;
writeln!(w, "type KVMap<K, V> = BTreeMap<K, V>;")?;
} else {
writeln!(w, "use std::collections::HashMap;")?;
writeln!(w, "type KVMap<K, V> = HashMap<K, V>;")?;
}
}
writeln!(
w,
"use quick_protobuf::{{MessageRead, MessageWrite, BytesReader, Writer, Result}};"
"use quick_protobuf::{{MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}};"
)?;

if self.owned {
write!(
w,
"\
use std::convert::TryFrom;\n\
use std::ops::Deref;\n\
use std::ops::DerefMut;\n\
use core::convert::TryFrom;\n\
use core::ops::Deref;\n\
use core::ops::DerefMut;\n\
"
)?;
}
Expand Down
1 change: 1 addition & 0 deletions perftest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ failure = "0.1.5"
protobuf-codegen-pure = "2.0.4"
pb-rs = { path = "../pb-rs" }
prost-build = "0.4.0"
[features]
2 changes: 2 additions & 0 deletions perftest/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ fn main() {
custom_rpc_generator: Box::new(|rpc, writer| generate_rpc_test(rpc, writer)),
custom_includes: Vec::new(),
owned: false,
hashbrown: false,
nostd: false,
};
FileDescriptor::write_proto(&config).unwrap();

Expand Down
Loading

0 comments on commit 5325627

Please sign in to comment.