Skip to content
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

[Rust] Support alloc-only no_std platforms #5366

Closed
wants to merge 6 commits into from

Conversation

jrobsonchase
Copy link

Hi! I'd love to be able to use flatbuffers on embedded systems, and it looks like it wouldn't be hard to support seeing as it's already 90% there.

This adds the #![no_std] attribute, changes all std imports to core, and pulls Vec from the alloc crate rather than std. I'd also love to see a StaticFlatBufferBuilder (or some such) that works only with ungrowable buffers, but that'll be a bigger change.

For platforms with std, this shouldn't change a thing - it just allows it to be used as a dependency for no_std crates.

@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here (e.g. I signed it!) and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

@jrobsonchase
Copy link
Author

Shoot, I keep forgetting that things that have been stabilized in nightly aren't necessarily stabilized in stable as well 😛

So I see two paths forward:

  1. Put no_std/alloc support behind a feature gate that'll need to be removed once alloc lands in stable so that the upstream flatbuffers crate can be used or
  2. Just sit on this PR until stable rust has the proper support and use a fork for now

Thoughts?

@jrobsonchase jrobsonchase force-pushed the no_std branch 4 times, most recently from d55d378 to 4ee7bcb Compare May 22, 2019 17:58
@rw
Copy link
Contributor

rw commented May 23, 2019

@jrobsonchase Wow, thanks for submitting this PR! no_std support would be great.

My first concern is ensuring that we work on stable Rust. After that, I'm happy to figure out how to support no_std. I like your idea of using a Cargo feature flag. Would stable and nightly users both be happy with that?

@jrobsonchase
Copy link
Author

It should be working on stable now via the default std flag. To make it work on no_std, you just specify default-features = false on the dependency and it'll add the no_std attr and pull in alloc, which is the way that no_std + alloc crates have been going about it these days.

I seem to have broken the generator tests. I think there were instructions in the PR guidelines that I skipped over because I wasn't originally planning on making any generator changes 😛 How do I go about making them happy again?

@rw
Copy link
Contributor

rw commented May 24, 2019

@jrobsonchase Cool!

Here's how you can fix it. There's a big error message in the middle of all the test output:

ERROR: ********************************************************
ERROR: The following differences were found after running the
ERROR: tests/generate_code.sh script.  Maybe you forgot to run
ERROR: it after making changes in a generator or schema?
ERROR: ********************************************************

https://travis-ci.org/google/flatbuffers/jobs/535909377

@rw
Copy link
Contributor

rw commented May 24, 2019

@jrobsonchase Is it feasible to add a new integration test file to this directory, to test this PR's functionality?

https://github.com/google/flatbuffers/tree/master/tests/docker/languages

@jrobsonchase
Copy link
Author

Sure, I can look into that :)

tests/RustTest.sh Outdated Show resolved Hide resolved
@rw
Copy link
Contributor

rw commented Jun 8, 2019

@jrobsonchase What do we need to do to get this finished? Thanks for starting it!

@jrobsonchase
Copy link
Author

It's ready to go as far as I can tell. The CI failure looks like an unrelated download problem.

Maybe travis needs a kick?

@jrobsonchase
Copy link
Author

@rw ping

@rw
Copy link
Contributor

rw commented Jun 28, 2019

@jrobsonchase Can you push a noop commit to trigger Travis? Then I'll check the logs to see that your new Dockerfile-based test ran successfully.

@rw
Copy link
Contributor

rw commented Oct 3, 2019

@jrobsonchase Looks like we accidentally let this PR languish, sorry about that! Are you still up for finishing it?

@aardappel aardappel force-pushed the master branch 3 times, most recently from f381fd7 to 31f8799 Compare December 26, 2019 20:36
@bbqsrc
Copy link

bbqsrc commented Feb 12, 2020

What's left to push this over the line?

@TheVova
Copy link

TheVova commented Feb 16, 2020

also asking whats left on this? if any help is needed let me know. i'd love to see this on embedded :)

@aardappel aardappel force-pushed the master branch 4 times, most recently from 6290611 to f116b80 Compare May 5, 2020 20:42
@github-actions github-actions bot added c++ codegen Involving generating code from schema labels Jun 19, 2021
@domenukk
Copy link

Missing no_std support is what keeps me from using flatbuffers, would be great to have from my PoV

@bbqsrc
Copy link

bbqsrc commented Jun 20, 2021

@rw this code is still needed for use in embedded environments. We use a fork in production as a workaround, and ultimately we'd prefer not to. 😉

@jacobrosenthal
Copy link

I've been following this issue for years as yes it would be nice to have for embedded. But really I'm actually waiting for the step further than this. The point of flatbuffers is zero copy, presumably zero allocation so its sad that allocation is still such a big part of even this pr. Most embedded code in rust land doesnt even use alloc partly because some allocator bits are still nightly only but mainly because the ecosystem is mostly real time nerds who are trying to avoid the original sin of allocation as much as they can.

@github-actions github-actions bot removed the stale label Jun 20, 2021
@bbqsrc
Copy link

bbqsrc commented Jun 21, 2021

While that may be so, the first step to getting to an alloc-less situation (such as by using heapless where necessary) is to have the crate build in #[no_std] at all.

@CasperN
Copy link
Collaborator

CasperN commented Jun 21, 2021

While that may be so, the first step to getting to an alloc-less situation (such as by using heapless where necessary) is to have the crate build in #[no_std] at all.

I think we may want to turn FlatBufferBuilder into a trait and have separate implementations. They could be specialized to different use cases E.g.

  • string pooling and even vtable deduplication might be unwanted in small environments - then there'd only be one vector in the builder, which could be replaced with a slice.
  • no-std with a provided custom allocator
  • no-std no allocator

This may require some minor rethinking of the API, e.g. use result types so we can fail to build a flatbuffer if the builder runs out of memory without just panic/abort.

@jrobsonchase
Copy link
Author

@rw This is ready for another review

Copy link
Member

@josephlr josephlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good! Thanks for working on this. Mostly some remaining nits.

rust/flatbuffers/src/lib.rs Outdated Show resolved Hide resolved
src/idl_gen_rust.cpp Outdated Show resolved Hide resolved
src/idl_gen_rust.cpp Outdated Show resolved Hide resolved
src/idl_gen_rust.cpp Outdated Show resolved Hide resolved
conan/travis/build.sh Show resolved Hide resolved
rust/flatbuffers/src/builder.rs Outdated Show resolved Hide resolved
my_game::example::Test::new(100, 101)
][..]
);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be sure to run rustfmt on this file (should have a trailing newline).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps there should be a CI check for formating. Generated files aside, almost everything has changes when cargo fmt is run.

rust/flatbuffers/Cargo.toml Outdated Show resolved Hide resolved
@josephlr
Copy link
Member

@jrobsonchase I think there are some more std usages that got missed.

If you run cargo build --no-default-features in the flatbuffers/rust/flatbuffers directory, the compiler should raise an error on the remaining usages. It looks like it's almost all just repacing std with core.

@josephlr
Copy link
Member

There's also the issue that thiserror doesn't yet support no_std. So it seems like an on-by-default "std" feature will be necessary (as that crate is used to derive the std::error::Error implementation for InvalidFlatbuffer). I've run into this issue before with getrandom, it's not too bad to fix.

First you want to make the dependency on thiserror optional, triggered by the "std", and on by default (as to not have a breaking change). So in the Cargo.toml do:

[dependencies]
smallvec = "1.6.1"
bitflags = "1.2.1"
thiserror = { version = "1.0.23", optional = true }

[features]
default = ["std"]
# Enable the std::error::Error implementation for InvalidFlatbuffer
std = ["thiserror"]

Then in verifier.rs:

// The thiserror crate requires use of libstd.
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "std")]
use thiserror::Error;

/// Describes how a flatuffer is invalid and, for data errors, roughly where. No extra tracing
/// information is given for DoS detecting errors since it will probably be a lot.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Error))]
pub enum InvalidFlatbuffer {
    #[cfg_attr(feature = "std", error("Missing required field `{required}`.\n{error_trace}"))]
    MissingRequiredField {
        required: &'static str,
        error_trace: ErrorTrace,
    },
    // etc...

This requires that you've made the changes to lib.rs (the the comment above) to make the crate unconditionally no_std.

@jrobsonchase
Copy link
Author

Thanks for the review - seems like things drifted further than I had thought in the time it was left to languish.

This includes making thiserror optional.

Additionally, tests are now run both with and without default features,
which will ensure that the runtime continues to build/run without std
support.
@jrobsonchase
Copy link
Author

@josephlr Ready for another look

@dbaileychess
Copy link
Collaborator

@josephlr @jrobsonchase What's the status of this review?

@dbaileychess
Copy link
Collaborator

Does #6989 solve this issue for you?

@dbaileychess
Copy link
Collaborator

Closing seeing #6989 seems to address the same thing. Please reopen if not the case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ codegen Involving generating code from schema grpc rust
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants