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

Serializing messages with no-alloc #440

Closed
zer0-droids opened this issue Oct 23, 2023 · 6 comments · Fixed by #441 or #442
Closed

Serializing messages with no-alloc #440

zer0-droids opened this issue Oct 23, 2023 · 6 comments · Fixed by #441 or #442

Comments

@zer0-droids
Copy link

Hello,

This is more a question than an issue.

I came across this crate recently and discovered that it has a no-alloc feature, which perfectly matches my environment. I've been able to implement a deserialization in my project, as it's done in example/wasm-hello-world/wasm-app/src/lib.rs, but I don't find a way to serialize a message.

Is it implemented for no-alloc? And if yes, would it be possible to have an example of use?

Thanks!

@dwrensha
Copy link
Member

You'll need to provide your own implementation of the Allocator trait:

/// An object that allocates memory for a Cap'n Proto message as it is being built.
/// Users of capnproto-rust who wish to provide memory in non-standard ways should
/// implement this trait. Objects implementing this trait are intended to be wrapped
/// by `capnp::private::BuilderArena`, which handles calling the methods at the appropriate
/// times, including calling `deallocate_segment()` on drop.
///
/// # Safety
/// Implementions must ensure all of the following:
/// 1. The memory returned by `allocate_segment` is initialized to all zeroes.
/// 2. The memory returned by `allocate_segment` is valid until `deallocate_segment()`
/// is called on it.
/// 3. The allocated memory does not overlap with other allocated memory.
/// 4. The allocated memory is 8-byte aligned (or the "unaligned" feature is enabled
/// for the capnp crate).
pub unsafe trait Allocator {
/// Allocates zeroed memory for a new segment, returning a pointer to the start of the segment
/// and a u32 indicating the length of the segment in words. The allocated segment must be
/// at least `minimum_size` words long (`minimum_size * 8` bytes long). Allocator implementations
/// commonly allocate much more than the minimum, to reduce the total number of segments needed.
/// A reasonable strategy is to allocate the maximum of `minimum_size` and twice the size of the
/// previous segment.
fn allocate_segment(&mut self, minimum_size: u32) -> (*mut u8, u32);
/// Indicates that a segment, previously allocated via allocate_segment(), is no longer in use.
/// `word_size` is the length of the segment in words, as returned from `allocate_segment()`.
/// `words_used` is always less than or equal to `word_size`, and indicates how many
/// words (contiguous from the start of the segment) were possibly written with non-zero values.
///
/// # Safety
/// Callers must only call this method on a pointer that has previously been been returned
/// from `allocate_segment()`, and only once on each such segment. `word_size` must
/// equal the word size returned from `allocate_segment()`, and `words_used` must be at
/// most `word_size`.
unsafe fn deallocate_segment(&mut self, ptr: *mut u8, word_size: u32, words_used: u32);
}

One way to do it would be to have a wrapper for a single &mut[u8]. That would work simlarly to ScratchSpaceHeapAllocator, except without the HeapAllocator for when the segment fills up. (You would need to panic when the segment fills.)

@zer0-droids
Copy link
Author

Thank you @dwrensha for the quick reply! I will have a look at this.

@dwrensha
Copy link
Member

I opened #441, which adds SingleSegmentAllocator.

@zer0-droids
Copy link
Author

Hi @dwrensha,

First, many thanks for the quick new release!

Unfortunately I still have issues to compile in my environment (no-std, no-alloc) something similar as the test case you added. The allocate_zeroed_vec() method returns a Vec which is not available, but it looks quite easy to fix, by passing to capnp::message::SingleSegmentAllocator::new() a reference to an aligned u8 slice.

The other problem I have seems harder to solve:

error[E0433]: failed to resolve: could not find Builderinmessage``

Indeed, the struct Builder is decorated with #[cfg(feature = "alloc")], so it is not available in my environment. We can't simply remove it since it depends on BuilderArenaImpl which uses a Vec.

@dwrensha dwrensha reopened this Oct 24, 2023
@dwrensha
Copy link
Member

Oops!

We need a no-alloc version of BuilderArenaImpl. The straightforward way to achieve that would be to hard code it to allow only one segment in the no-alloc case.

@dwrensha
Copy link
Member

I opened #442.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants