2806772fd1
Gate generated code behind feature flags so consumers can build in no_std/no_alloc environments: - Runtime: gate RotoMessage, RotoOwned, BufMutBuilder behind alloc - Codegen: split DATA_IMPORTS, gate Owned* structs + service code - Fix RevBuilder::with() to iterate forward without Vec allocation - Wire up bytes/std via alloc feature (Bytes requires Arc) - Update consumer Cargo.toml files with proper feature chains - Add no_std_test example for embedded validation
4.4 KiB
4.4 KiB
Task: Verify Generated Code Works in no_std / no_alloc
Goal: Ensure all generated protobuf code compiles and runs in no_std + no_alloc environments. Features requiring alloc must be gated behind feature flags in the proto generator's output.
Status: ✅ COMPLETE
Findings
Already clean (no_std + no_alloc):
- All reader structs (
Message<'a>) — zero-copy accessors over&[u8] - All field accessors, enums, builders (
MessageBuilder<'b>), typed iterators - Core runtime:
ProtoAccessor,ProtoBuilder,RevBuilder,read_varint,write_varint, all iterators
Needs alloc feature gate:
RotoMessagetrait — usesbytes::Bytes(hasArcinternally)RotoOwnedtrait — same issueOwnedMessagestructs generated by codegenRevBuilder::with()— usesVec<_>to collect raw fieldsBytes,BytesMutimports inDATA_IMPORTS
Needs std feature gate:
- All service code (
SERVICE_IMPORTS) — usesstd::sync::Arc,std::pin::Pin,String, etc. std::error::Error for RotoError(already gated)
Plan
Phase 1: Runtime (runtime/src/lib.rs, runtime/Cargo.toml) ✅
GateRotoMessageandRotoOwnedbehind#[cfg(feature = "alloc")]GateBufMutBuilderbehind#[cfg(feature = "alloc")]Gateuse bytes::BufMut— only import it conditionallyWire upbytesfeatures in Cargo.toml:
Note: bytes::Bytes requires Arc internally, which is in std. Since bytes only has a std feature (no separate alloc), our alloc feature implies std:
[features]
default = ["std", "alloc"]
std = []
alloc = ["std", "bytes/std"]
Phase 2: Codegen — DATA_IMPORTS & Generated Data Code (codegen/src/generator/mod.rs) ✅
SplitDATA_IMPORTSinto unconditional + gated sectionsGateOwnedMessagestructs +RotoMessageimpls with#[cfg(feature = "alloc")]FixRevBuilder::with()— replacedVec::collect()+.rev()with forward iteration
Phase 3: Codegen — Service Code (codegen/src/generator/mod.rs) ✅
GateSERVICE_IMPORTSwith#[cfg(feature = "std")]Gate all service traits, server impls, and*Serverstructs with#[cfg(feature = "std")]
Phase 4: Generated Consumer Setup ✅
Emit aCargo.toml(or instruct consumers) with the right feature setup
Updated consumer Cargo.toml files:
examples/hello_world/Cargo.tomlroto-tonic/Cargo.tomlbenches/Cargo.toml
[features]
default = ["std"]
std = ["roto-runtime/std", "alloc"]
alloc = ["roto-runtime/alloc"]
Phase 5: Validation ✅
Updateexamples/no_std_testto build with--no-default-featuresRun existing tests with default featuresAdd a compile-test that verifies--no-default-featuresbuilds succeed
Dependency Graph
no_std + no_alloc → readers, enums, builders, iterators
↓ alloc → + OwnedMessage, RotoMessage trait (implies std via bytes::Bytes)
↓ std → + service code, std::error::Error
Files Modified
| File | Changes |
|---|---|
runtime/src/lib.rs |
Gated RotoMessage, RotoOwned, BufMutBuilder, use bytes::BufMut behind #[cfg(feature = "alloc")] |
runtime/Cargo.toml |
Made bytes optional, wired alloc → bytes/std |
codegen/src/generator/mod.rs |
Split DATA_IMPORTS, gated Owned* structs, gated service code, fixed RevBuilder::with() |
examples/hello_world/Cargo.toml |
Added std/alloc feature wiring |
roto-tonic/Cargo.toml |
Added std/alloc feature wiring |
benches/Cargo.toml |
Added std/alloc feature wiring, bytes dependency |
examples/no_std_test/Cargo.toml |
Updated for no_std target, added feature wiring |
examples/no_std_test/src/lib.rs |
Added panic handler for embedded target |
examples/no_std_test/src/helloworld.rs |
Rewrote as minimal gated example |
Validation
- ✅
cargo build— all packages build with default features - ✅
cargo build --package roto-runtime --no-default-features— runtime builds without alloc - ✅
cargo test --all— 38 tests pass (runtime + codegen + integration) - ✅
examples/no_std_testbuilds with--no-default-featuresonthumbv7em-none-eabihftarget - ✅ Generated code from integration test (
test_helloworld_build) compiles successfully