Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ members = [
"crates/nexum-venue-sdk",
"crates/nexum-venue-test",
"crates/nexum-world",
"crates/no-std-probe",
"crates/shepherd",
"crates/shepherd-backtest",
"crates/shepherd-cow-host",
Expand Down
2 changes: 2 additions & 0 deletions crates/cow-venue/src/composable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
//! `static_input` is opaque to the venue; only the named handler parses
//! it, so this crate never inspects its bytes.

use alloc::vec::Vec;

use borsh::{BorshDeserialize, BorshSerialize};

use crate::order::Address;
Expand Down
11 changes: 7 additions & 4 deletions crates/cow-venue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
//! venue SDK (for the [`IntentBody`](nexum_venue_sdk::IntentBody) derive)
//! and borsh, so a venue adapter component or a strategy module can carry
//! the body types and codec without dragging in the host-side CoW
//! machinery. The one non-obvious constraint: the derive's generated code
//! names `::std`, so the slice links std and is not a bare-metal
//! `#![no_std]` crate; it is guest-consumable on the runtime's
//! std-bearing wasm target rather than target-free.
//! machinery. The crate is `#![no_std]` (tests aside): the derive's
//! generated code reaches `alloc` through the venue SDK re-export, never
//! `::std`.
//!
//! With `--no-default-features` the slice drops out entirely and the
//! crate compiles empty, so a consumer can depend on a future slice
Expand All @@ -26,9 +25,13 @@
//! so an adapter or a module that wants only the body types stays
//! dependency-light.

#![cfg_attr(not(test), no_std)]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Checked the actual owning crate of IntentBody/BodyError/__private::allocnexum-venue-sdk's lib.rs has no #![no_std] attribute anywhere (confirmed at this PR's head commit); it's a regular std crate. cow-venue depends on it unconditionally for the body feature. #![no_std] on cow-venue only governs this crate's own prelude/source, it doesn't make the dependency graph no_std-capable — building for a genuine bare-metal target (no std implementation at all, unlike wasm32-wasip2 which the PR body itself notes is "std-bearing") would almost certainly fail at nexum-venue-sdk's own compilation step, before cow-venue is even reached. The repo's only specialized target config (.cargo/config.toml) is wasm32-wasip2, and there's no CI job or just recipe building against an actual no-std-only target triple (e.g. thumbv7em-none-eabi) — so the stated goal ("blocked bare-metal consumers" → unblocked) is checked only by cargo check on the default host target, where std is trivially available regardless of any #![no_std] attribute. Worth either converting nexum-venue-sdk itself to #![no_std] (if that's feasible), or scoping the PR's claim down to "the derive no longer hardcodes ::std paths" rather than "unblocks bare-metal consumers," since that part is unverified and likely not yet true.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed still valid at HEAD. videre-sdk (the IntentBody owner post-rename) still carries no #![no_std] at the tip, and there is no CI/just build against a real no-std triple - only wasm32-wasip2 (std-bearing) and host cargo check. The derive itself is clean; the bare-metal goal is unverified and, per the unconditional videre-sdk dependency, not yet reachable. Tracked in #521, with your scope-down alternative recorded there.

#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![warn(missing_docs)]

#[cfg(feature = "body")]
extern crate alloc;

#[cfg(feature = "body")]
pub mod body;

Expand Down
14 changes: 9 additions & 5 deletions crates/nexum-macros/src/intent_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
//!
//! Generated code names the venue SDK by its crate path
//! (`::nexum_venue_sdk`), so the derive is only usable through that
//! crate's re-export.
//! crate's re-export. The expansion names only `::core` and the SDK's
//! `__private` re-exports (borsh, `alloc`), so a `#![no_std]` consumer
//! needs no `extern crate alloc`.

use proc_macro2::TokenStream;
use quote::quote;
Expand Down Expand Up @@ -80,12 +82,12 @@ pub(crate) fn expand(input: &DeriveInput) -> syn::Result<TokenStream> {

encode_arms.push(quote! {
Self::#ident(payload) => {
let mut out = ::std::vec::Vec::new();
let mut out = ::nexum_venue_sdk::body::__private::alloc::vec::Vec::new();
out.push(#tag);
::nexum_venue_sdk::body::__private::borsh::to_writer(&mut out, payload).map_err(
|err| ::nexum_venue_sdk::body::BodyError::Encode {
version: #tag,
detail: ::std::string::ToString::to_string(&err),
detail: ::nexum_venue_sdk::body::__private::alloc::string::ToString::to_string(&err),
},
)?;
::core::result::Result::Ok(out)
Expand All @@ -96,7 +98,9 @@ pub(crate) fn expand(input: &DeriveInput) -> syn::Result<TokenStream> {
::nexum_venue_sdk::body::__private::borsh::from_slice::<#payload_ty>(payload)
.map_err(|err| ::nexum_venue_sdk::body::BodyError::Malformed {
version: #tag,
detail: ::std::string::ToString::to_string(&err),
detail: ::nexum_venue_sdk::body::__private::alloc::string::ToString::to_string(
&err,
),
})?,
)),
});
Expand All @@ -108,7 +112,7 @@ pub(crate) fn expand(input: &DeriveInput) -> syn::Result<TokenStream> {
fn to_bytes(
&self,
) -> ::core::result::Result<
::std::vec::Vec<u8>,
::nexum_venue_sdk::body::__private::alloc::vec::Vec<u8>,
::nexum_venue_sdk::body::BodyError,
> {
match self {
Expand Down
5 changes: 4 additions & 1 deletion crates/nexum-venue-sdk/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,11 @@ impl From<BodyError> for VenueError {
}

/// Re-exports for `#[derive(IntentBody)]` generated code only; not a
/// public surface.
/// public surface. `alloc` rides along so the expansion resolves in a
/// `#![no_std]` consumer without its own `extern crate alloc`.
#[doc(hidden)]
pub mod __private {
pub extern crate alloc;

pub use borsh;
}
18 changes: 18 additions & 0 deletions crates/no-std-probe/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "no-std-probe"
version = "0.1.0"
edition.workspace = true
license.workspace = true
repository.workspace = true
description = "Compile-only #![no_std] probe: the IntentBody derive must expand without the consumer's std prelude."

[lib]
# Never shipped. Living in the workspace keeps the derive's no_std
# contract under the workspace check/clippy gate.

[lints]
workspace = true

[dependencies]
# Source of the `IntentBody` derive and trait the probe enum implements.
nexum-venue-sdk = { path = "../nexum-venue-sdk" }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Relatedly: this direct dependency on nexum-venue-sdk is exactly the path through which a genuine no-std-target build would fail (see the cow-venue/lib.rs:28 comment) — the probe only proves the derive macro's generated code doesn't reference ::std textually, not that the crate graph can target a real bare-metal platform. Also, separately: the probe only derives IntentBody on ProbeBody, it never calls to_bytes/from_bytes — so it proves macro expansion under no_std, not correctness of the generated round-trip logic. A #[cfg(test)] mod tests block (tests are exempted from the no_std attribute per the cow-venue pattern) exercising an actual encode/decode round-trip would close that gap cheaply.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed still valid at HEAD - the no-std-probe at the tip still only derives IntentBody without a round-trip. A #[cfg(test)] encode/decode test (exempt from #![no_std], per the cow-venue pattern) would prove the generated logic, not just expansion. Folded into #521.

14 changes: 14 additions & 0 deletions crates/no-std-probe/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Compile-only `#![no_std]` probe: `#[derive(IntentBody)]` must expand
//! without the consumer's std prelude or an `extern crate alloc`.

#![no_std]
#![warn(missing_docs)]

use nexum_venue_sdk::IntentBody;

/// The probe schema: one published version over a bare byte payload.
#[derive(IntentBody, Clone, Debug, PartialEq, Eq)]
pub enum ProbeBody {
/// First published version.
V1(u8),
}
Loading