pub enum AnyChunk<const BODY_SIZE: usize = DEFAULT_BODY_SIZE> {
Content(ContentChunk<BODY_SIZE>),
SingleOwner(SingleOwnerChunk<BODY_SIZE>),
}Expand description
Type-erased chunk for runtime polymorphism with configurable body size.
This enum provides dynamic dispatch for chunks without requiring object-safe traits. Use this when you need to store heterogeneous chunk types in collections or pass chunks through interfaces that can’t be generic.
§Why an enum instead of Box<dyn Chunk>?
The Chunk trait has an associated type (type Header) which makes it not
object-safe. This enum provides the same functionality while maintaining type safety.
§Examples
use nectar_primitives::{AnyChunk, Chunk, ContentChunk, ChunkTypeId};
// Create a content chunk
let content = ContentChunk::new(&b"hello world"[..]).unwrap();
let any: AnyChunk = content.clone().into();
// Access common properties
assert_eq!(any.type_id(), ChunkTypeId::CONTENT);
// Get the concrete type back
if let Some(recovered) = any.as_content() {
assert_eq!(recovered.address(), content.address());
}Variants§
Content(ContentChunk<BODY_SIZE>)
A content-addressed chunk (CAC).
SingleOwner(SingleOwnerChunk<BODY_SIZE>)
A single-owner chunk (SOC).
Implementations§
Source§impl<const BODY_SIZE: usize> AnyChunk<BODY_SIZE>
impl<const BODY_SIZE: usize> AnyChunk<BODY_SIZE>
Sourcepub fn address(&self) -> &ChunkAddress
pub fn address(&self) -> &ChunkAddress
Get the address of this chunk.
Sourcepub const fn type_id(&self) -> ChunkTypeId
pub const fn type_id(&self) -> ChunkTypeId
Get the type ID of this chunk.
Sourcepub fn span(&self) -> u64
pub fn span(&self) -> u64
Get the span (logical data length) of this chunk: the BMT span of its underlying body.
Sourcepub fn transformed_address(&self, anchor: &[u8]) -> ChunkAddress
pub fn transformed_address(&self, anchor: &[u8]) -> ChunkAddress
Compute the anchor-keyed transformed address of this chunk.
The transformed address is the redistribution sampler’s per-round,
per-node re-hash of a chunk. It is a prefixed BMT root keyed by the
node’s anchor, used to order reserve chunks deterministically while
binding the ordering to the proving node. This reproduces bee’s
storer.transformedAddress (pkg/storer/sample.go) byte-for-byte.
§Derivation
- For a content-addressed chunk (CAC) the transformed address is the
prefixed BMT of the chunk body, i.e.
BMT(prefix = anchor, span, payload). This is computed byBmtBody::transformed_rooton the chunk’s borrowed body, which mixes the anchor into every node hash, matching bee’s prefix hasher. - For a single-owner chunk (SOC) the wrapped content body is re-hashed
the same way to obtain
inner, then the SOC’s transformed address is a plain, unprefixedkeccak256(soc_address || inner). The outer wrap is a flat Keccak256, not a prefixed BMT, mirroring bee’stransformedAddressSOCwhich usesswarm.NewHasher()(no anchor) for the final combine.
§Endianness
The span is serialised little-endian inside the BMT. Do not confuse this with the big-endian encodings used elsewhere on the redistribution wire (e.g. proof witness indices); the BMT span is always LE.
§Borrowing
The CAC and SOC paths dispatch through borrowed body accessors
(ContentChunk::body and SingleOwnerChunk::inner_body), so no
chunk or body is cloned. For a SOC the wrapped body already is the
content chunk’s span || payload, so the inner root needs no
32 + 65 (id + signature) header slicing.
Sourcepub fn verify(&self, expected: &ChunkAddress) -> Result<()>
pub fn verify(&self, expected: &ChunkAddress) -> Result<()>
Verify that this chunk’s address matches an expected address.
Sourcepub fn into_bytes(self) -> Bytes
pub fn into_bytes(self) -> Bytes
Convert this chunk into its serialized bytes representation.
Sourcepub const fn is_content(&self) -> bool
pub const fn is_content(&self) -> bool
Check if this is a content chunk.
Sourcepub const fn is_single_owner(&self) -> bool
pub const fn is_single_owner(&self) -> bool
Check if this is a single-owner chunk.
Sourcepub const fn as_content(&self) -> Option<&ContentChunk<BODY_SIZE>>
pub const fn as_content(&self) -> Option<&ContentChunk<BODY_SIZE>>
Get a reference to the contained ContentChunk, if this is one.
Sourcepub const fn as_single_owner(&self) -> Option<&SingleOwnerChunk<BODY_SIZE>>
pub const fn as_single_owner(&self) -> Option<&SingleOwnerChunk<BODY_SIZE>>
Get a reference to the contained SingleOwnerChunk, if this is one.
Sourcepub fn into_content(self) -> Option<ContentChunk<BODY_SIZE>>
pub fn into_content(self) -> Option<ContentChunk<BODY_SIZE>>
Convert into the contained ContentChunk, if this is one.
Sourcepub fn into_single_owner(self) -> Option<SingleOwnerChunk<BODY_SIZE>>
pub fn into_single_owner(self) -> Option<SingleOwnerChunk<BODY_SIZE>>
Convert into the contained SingleOwnerChunk, if this is one.
Sourcepub fn to_typed_bytes(&self) -> Vec<u8> ⓘ
pub fn to_typed_bytes(&self) -> Vec<u8> ⓘ
Encode this chunk as a type-tagged, self-describing byte string.
The layout is [type_id: 1 byte][chunk wire bytes], where the chunk
wire bytes are the same form produced by AnyChunk::into_bytes (the
inverse of ContentChunk::try_from/SingleOwnerChunk::try_from).
The chunk address is deliberately not embedded. It is supplied from context on decode (for example the redb key when reading from storage, or the address field of a wire message). This mirrors the existing reconstruction paths that take an expected address.
Unlike the address-disambiguating reconstruction path, decoding the
result of this method dispatches purely by type_id, so it never has
to trial-parse both the content and single-owner shapes.
§Examples
use nectar_primitives::{AnyChunk, Chunk, ContentChunk};
let content = ContentChunk::new(&b"hello world"[..]).unwrap();
let address = *content.address();
let any: AnyChunk = content.into();
let encoded = any.to_typed_bytes();
assert_eq!(encoded[0], 0); // CONTENT type id
let decoded: AnyChunk = AnyChunk::from_typed_bytes(&address, &encoded).unwrap();
assert_eq!(decoded.address(), any.address());Sourcepub fn from_typed_bytes(address: &ChunkAddress, bytes: &[u8]) -> Result<Self>
pub fn from_typed_bytes(address: &ChunkAddress, bytes: &[u8]) -> Result<Self>
Decode a type-tagged chunk produced by AnyChunk::to_typed_bytes.
The leading byte selects the chunk type and the remainder is the chunk
wire payload. address is the expected chunk address (for example the
redb storage key or the wire message address field); the decoded chunk
is verified against it.
Decoding dispatches by the type tag and therefore never trial-parses the other chunk shape. Only the standard content and single-owner types are recognised; any other tag is an error (custom chunk types are tracked separately as a future registration mechanism).
§Errors
Returns an error (and never panics) when:
- the input is empty (no type tag),
- the type tag is not a recognised standard chunk type,
- the payload cannot be decoded as the tagged chunk type, or
- a standard chunk’s computed address does not match
address.
Sourcepub fn from_wire_bytes(address: &ChunkAddress, data: Bytes) -> Result<Self>
pub fn from_wire_bytes(address: &ChunkAddress, data: Bytes) -> Result<Self>
Decode a chunk from its bare wire bytes (NO type tag) given the expected
address, disambiguating content vs single-owner by which one hashes to
address. This is the type-less wire form (e.g. a Delivery data
field); prefer from_typed_bytes for
self-describing storage. Only content and single-owner shapes are
recognised; bytes that parse as neither (for the given address) error.
Reconstructing an AnyChunk from raw bytes is ambiguous without the
address: a ContentChunk parse almost always succeeds structurally (a
span plus an arbitrary payload), so the expected address is the
disambiguator. The chunk is whichever variant parses and hashes to
address. Content is tried first, then single-owner; a lying address
makes both attempts fail, so the address is self-validating against the
bytes.
§Errors
Returns a verification error (and never panics) when neither the content
nor the single-owner interpretation of data hashes to address.
Trait Implementations§
impl<const BODY_SIZE: usize> Eq for AnyChunk<BODY_SIZE>
Source§impl<const BODY_SIZE: usize> From<ContentChunk<BODY_SIZE>> for AnyChunk<BODY_SIZE>
impl<const BODY_SIZE: usize> From<ContentChunk<BODY_SIZE>> for AnyChunk<BODY_SIZE>
Source§fn from(chunk: ContentChunk<BODY_SIZE>) -> Self
fn from(chunk: ContentChunk<BODY_SIZE>) -> Self
Source§impl<const BODY_SIZE: usize> From<SingleOwnerChunk<BODY_SIZE>> for AnyChunk<BODY_SIZE>
impl<const BODY_SIZE: usize> From<SingleOwnerChunk<BODY_SIZE>> for AnyChunk<BODY_SIZE>
Source§fn from(chunk: SingleOwnerChunk<BODY_SIZE>) -> Self
fn from(chunk: SingleOwnerChunk<BODY_SIZE>) -> Self
Auto Trait Implementations§
impl<const BODY_SIZE: usize = DEFAULT_BODY_SIZE> !Freeze for AnyChunk<BODY_SIZE>
impl<const BODY_SIZE: usize> RefUnwindSafe for AnyChunk<BODY_SIZE>
impl<const BODY_SIZE: usize> Send for AnyChunk<BODY_SIZE>
impl<const BODY_SIZE: usize> Sync for AnyChunk<BODY_SIZE>
impl<const BODY_SIZE: usize> Unpin for AnyChunk<BODY_SIZE>
impl<const BODY_SIZE: usize> UnsafeUnpin for AnyChunk<BODY_SIZE>
impl<const BODY_SIZE: usize> UnwindSafe for AnyChunk<BODY_SIZE>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more