-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add no_std support using alloc collections #148
Conversation
This replaces all public uses of the Writer trait with the new WriterBackend, which defines only the interaction points which are actually used. It also introduces the BytesWriter struct as a new implementation of WriterBackend that will work in no_std, along with the serialize_into_slice convenience fn. This is technically a breaking change, as it will require stubs to be regenerated.
- Add the `std` feature to the quick-protobuf runtime crate - Put uses of Vec and std::io::Write behind the `std` feature - Change other uses of `std` to `core` - Add the `quick-protobuf/no-std-example` compile test
…nostd mode; regenerate nostd test proto
Weird, after reloading the page github is no longer complaining about merge commits. Let me know if you need anything else. |
@@ -0,0 +1,868 @@ | |||
// Automatically generated rust module for 'test_basic_pb.proto' file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this file get removed from the PR? We are going to keep only a couple generated files and the no-std-example above shows what the --nostd
codegen looks like. Looks like the file should get added to the gitignore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
perftest/src/perftest_data.rs
Outdated
@@ -1,4 +1,4 @@ | |||
// This file is generated by rust-protobuf 2.8.0. Do not edit | |||
// This file is generated by rust-protobuf 2.8.1. Do not edit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this file checked in? I couldn't tell when I removed a bunch of other generate files if this one could go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to check this one I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
run_test.sh
Outdated
@@ -8,4 +8,9 @@ cargo run -p quick-protobuf --example pb_rs_example_v3_owned | |||
cargo run -p quick-protobuf --example pb_rs_example | |||
cargo run -p quick-protobuf --example pb_rs_example_v3 | |||
|
|||
# test that no_std can build | |||
pushd quick-protobuf/no-std-example |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we condense the example into a single file the rest of the examples? I assume the feature toggling makes it a little trickier... If it isn't too much work, it'd be nice to have it be consistent with the other examples.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -99,6 +99,23 @@ message TestTypesRepeated { | |||
repeated TestEnumDescriptor enum_field = 16 [packed=false]; | |||
} | |||
|
|||
message TestTypesRepeatedArrayVec { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need this new message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR!
On top of what @nerdrew said, could you please remove the HashMap
aliasing and review the extern crate
declarations.
{ | ||
writeln!(w, "use std::borrow::Cow;")?; | ||
if config.nostd { | ||
writeln!(w, "extern crate alloc;")?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure but the extern crate
may be repeated many times when implemented this way. Won't the rust compiler complain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't appear to happen in the example, as you can see in the file quick-protobuf/examples/pb_rs_nostd/protos/no_std.rs after run_test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added an extern crate alloc;
to pb_rs_example_nostd.rs
, the compiler doesn't care that the create is extern'd twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. Sounds weird to me.
writeln!(w, "use std::collections::HashMap;")?; | ||
if config.nostd { | ||
writeln!(w, "use alloc::collections::BTreeMap;")?; | ||
writeln!(w, "pub type HashMap<K, V> = BTreeMap<K, V>;")?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather use a BTreeMap
directly here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems good to have client code not care about which mode the proto is compiled in, in the default case. Why do you prefer to have separate APIs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like misleading APIs. HashMap
conveys a O(1) and a Hash key instead of a O(log(n)) and a Ord key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kinda like the suggestion of depending on hashbrown directly. Would adding that dependency in a no_std env be acceptable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i actually dont like this at all. in general in no_std you dont want too many dependencies, because the status of your code being 'no_std' depends on all the dependencies (including transitive ones) being no_std, which can get annoying. i see the utility of having support for all protobuf types, but i still think that you should feature-gate this, and have the dependency as optional for this feature (like features = ["hashmap"], etc.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A feature gate makes sense, though I think we can probably just do a build flag instead since this is just for generated code. pb-rs --hashmap
or something like that. Would you want it to error if the proto has a map type but --hashmap
isn't enabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I assume --hashmap
would use hashbrown
or something similar if enabled?
Hmmm. We would need a feature-gate + the pb-rs
flag I think. Feature-gate for quick-protobuf and flag for pb-rs
....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah exactly, i agree on the flag + feature. as for errors, it would make most sense to error in case of mismatch. the more interesting way to deal with this (IMHO) is actually given in the protobuf api itself. see https://developers.google.com/protocol-buffers/docs/proto#maps, under "Backwards compatibility". especially the requirement that "Any protocol buffers implementation that supports maps must both produce and accept data that can be accepted by the above definition." Which technically means we can still be wire-compatible even without depending on anything. this is arguably more work to implement, and is probably outside the scope of this PR, but something to think about. as a corollary this probably also means that pb-rs doesnt actually comply with the protobuf specification?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True. I hadn't thought about the maps-are-really-just-a-repeated-field aspect. I like that as the default. I suppose we'd just create a synthetic nested message for the map field in the generated code.
writeln!(w, "use std::borrow::Cow;")?; | ||
|
||
if config.nostd { | ||
writeln!(w, "extern crate alloc;")?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment for the repeated extern crate
calls. Usually the files generated by pb-rs will be modules to be inserted into wider project. I believe the extern crate declarations should be in the lib.rs
or main.rs
file, not here. We could probably trigger some cli message or add a comment in every file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think agree with this. The usability of requiring an extern crate ...
in your code to use no_std is sub-optimal, but I like the explicitness of it. I don't really like changing global properties because you included some generated code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see the official take on this from when alloc was stabilised:
https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html#the-alloc-crate-is-stable
so this should be on lib.rs, yes.
perftest/src/perftest_data.rs
Outdated
@@ -1,4 +1,4 @@ | |||
// This file is generated by rust-protobuf 2.8.0. Do not edit | |||
// This file is generated by rust-protobuf 2.8.1. Do not edit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to check this one I think
Thanks for the changes, I didn't see them. Could you fix the fmt issue? @nerdrew any more comment? |
whats the status with this? i'd have much use of this being no_std... if i can help fix issues let me know. As for HashMap vs B-Tree, i agree with @tafia , changing abstractions like this isnt good. The fact that you put a no_std flag on your library already means there are certain choices you will have to make explicitly. in no_std context the client does and should care about the implementation to a degree. i use Rust pretty exclusively in embedded context (so no_std), and known performance and being sure of whats implemented is important. The correct solution (imho, and as done in most no_std crates) is to feature-gate this type (i.e normally hasmaps are not supported), and if you explicitly opt-in (opt-in to the hashmap feature, not no_std in general), then make it clear the type is changed to BtreeMap. |
Hi all, I'd like to join to you efforts to make quick-protobuf I suggest to try hashbrown for map types in |
@xoloki would you be able to make the changes we discussed on the PR or should someone else make another one? |
This PR builds on the work of @mullr in #145 but uses the alloc crate for vector and map types when in no_std mode.
pb-rs now takes a new flag (--nostd). When this flag is passed, the generated Rust code will use alloc::vec::Vec and alloc::collections::BTreeMap. BTreeMap<K,V> will be typedef'd to HashMap<K,V>, so client code will not need to do anything different in std vs no_std modes.