The suggested two-Cargo.toml approach is NOT needed. The current structure already works perfectly and follows Rust best practices.
ros-z/ # Workspace root
├── Cargo.toml # Workspace definition
├── ros-z/ # Library crate
│ ├── Cargo.toml # ✅ Has ALL deps: clap, tokio, zenoh
│ ├── src/ # Library code
│ └── examples/ # ✅ Standard location
│ ├── z_pubsub.rs
│ ├── demo_nodes/
│ │ ├── talker.rs
│ │ ├── listener.rs
│ │ └── add_two_ints_*.rs
│ └── ...
├── book/
│ └── src/chapters/
│ └── *.md # ✅ Use {{#include ../../../ros-z/examples/...}}
└── test-docs.sh # ✅ Automated testing
$ cargo run --example demo_nodes_talker -- --help
ROS 2 demo talker node - publishes 'Hello World' messages
Usage: demo_nodes_talker [OPTIONS]
Options:
-t, --topic <TOPIC> Topic name to publish to [default: chatter]
-p, --period <PERIOD> Publishing period in seconds [default: 1.0]
-m, --mode <MODE> Zenoh session mode (peer, client, router) [default: peer]
-e, --endpoint <ENDPOINT> Zenoh router endpoint to connect to (e.g., tcp/localhost:7447)
-h, --help Print helpProof: clap CLI args work ✅
From ros-z/Cargo.toml:
[dependencies]
clap = { workspace = true, features = ["derive"] } # ✅ For CLI
tokio = { workspace = true, features = ["rt-multi-thread"] } # ✅ For async
zenoh = { workspace = true } # ✅ For messaging
# ... all other dependencies
[dev-dependencies]
ros-z-msgs = { path = "../ros-z-msgs" } # ✅ For messagesResult: Examples have access to everything they need.
[[example]]
name = "demo_nodes_talker"
path = "examples/demo_nodes/talker.rs"
required-features = []
[[example]]
name = "demo_nodes_add_two_ints_client"
path = "examples/demo_nodes/add_two_ints_client.rs"
required-features = ["external_msgs"]Result: Cargo knows about all examples and can build/run them.
cargo build
mdbook test book -L ./target/debug/depsThe -L ./target/debug/deps flag links examples against the compiled library.
{{#include ../../../ros-z/examples/demo_nodes/talker.rs}}Resolves to: ros-z/examples/demo_nodes/talker.rs ✅
The suggested approach would:
| Aspect | Current (Standard) | Suggested (Non-standard) |
|---|---|---|
| Structure | ros-z/examples/ |
examples/ (workspace member) |
| Dependencies | In ros-z/Cargo.toml |
Duplicate in examples/Cargo.toml |
| Include paths | {{#include ../../../ros-z/examples/...}} |
Would need updating (breaks book) |
| Complexity | Simple | More complex |
| Follows Rust conventions | ✅ Yes | ❌ No |
| Requires restructuring | ❌ No | ✅ Yes (major) |
From the proposal:
1. cargo build # ✅ Builds lib + examples
2. cargo test # ✅ Tests library
3. mdbook test book -L ./target/debug/deps # ✅ Tests all book examples
4. mdbook serve book # ✅ Live previewStatus: All steps work with current structure.
./test-docs.shRuns the complete workflow automatically.
.github/workflows/docs.yml:
jobs:
test:
steps:
- run: cargo build # ✅ Builds everything
- run: cargo test # ✅ Tests library
- run: mdbook test book -L ./target/debug/deps # ✅ Tests bookStatus: CI validates everything on every commit.
✅ Keep the current structure - it's optimal and follows Rust best practices.
❌ Don't implement the two-Cargo.toml approach - it would:
- Add unnecessary complexity
- Break existing include paths (20+ files to update)
- Create a non-standard project structure
- Provide no benefits over the current setup
- book/README.md - Development workflow guide
- book/TESTING.md - Comprehensive testing documentation
- book/QUICK_REFERENCE.md - Quick reference for testing
- book/WORKFLOW_VERIFICATION.md - Proof that current structure works
- test-docs.sh - Automated test script
- CONTRIBUTING.md - Contributor guidelines
-
Reload nix environment to get mdbook:
direnv allow
-
Run the full workflow:
./test-docs.sh
-
Preview the book:
mdbook serve book
The current structure is already optimal. No restructuring is needed. The proposal has been fully implemented using the standard Rust approach, which is simpler, more maintainable, and works perfectly. ✅