Skip to content

feat(map)!: add Send + Sync supertraits to Value#126

Open
msumme wants to merge 4 commits into
tweedegolf:masterfrom
msumme:value-send-sync
Open

feat(map)!: add Send + Sync supertraits to Value#126
msumme wants to merge 4 commits into
tweedegolf:masterfrom
msumme:value-send-sync

Conversation

@msumme
Copy link
Copy Markdown

@msumme msumme commented Apr 13, 2026

Summary

  • Add Send + Sync supertraits to the Value trait so that futures returned by MapStorage::store_item (and other methods) are Send.
  • store_item_inner uses &dyn Value<'_> internally. For &dyn T to be Send, T must be Sync — without the supertrait, the future is !Send even when the concrete value type is Send + Sync.
  • All existing Value implementations (primitives, &[u8], Option<T>, postcard types) are already Send + Sync, so this is unlikely to break real-world code.
  • Adds a compile-time assertion test to prevent regression.

Changes

  • src/map.rs: Value<'a> now requires Send + Sync
  • src/map.rs: Added _assert_store_item_future_is_send compile-time test
  • CHANGELOG.md: Added breaking change entry under Unreleased

Related Issues

Closes #125

Test Plan

  • All 52 existing unit tests pass
  • New compile-time test verifies the store_item future is Send
  • Removing the supertraits causes the new test to fail with the expected error

The Value trait's lack of Send/Sync bounds caused futures returned by
MapStorage methods to be !Send, since store_item_inner uses &dyn Value
which requires Sync on the trait object for the reference to be Send.

Closes tweedegolf#125
Comment thread src/map.rs Outdated

/// Compile-time check: the future returned by `store_item` must be `Send`
/// when all components are `Send`. See https://github.com/tweedegolf/sequential-storage/issues/125
fn _assert_store_item_future_is_send() {
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

You can use this test to verify that both Send + Sync are needed. Happy to remove it if not deemed valuable moving forward.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you add the same check for fetch_item I'd be happy with it :)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done!

@msumme msumme marked this pull request as ready for review April 14, 2026 00:32
Comment thread src/map.rs Outdated
/// It also carries a lifetime so that zero-copy deserialization is supported.
/// Zero-copy serialization is not supported due to technical restrictions.
pub trait Value<'a> {
pub trait Value<'a>: Send + Sync {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sync doesn't really make sense to me... Why did you add it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It didn't make sense to me at first either.
https://doc.rust-lang.org/src/core/marker.rs.html

// Most instances arise automatically, but this instance is needed to link up `T: Sync` with
// `&T: Send` (and it also removes the unsound default instance `T Send` -> `&T: Send` that would
// otherwise exist).
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Sync + PointeeSized> Send for &T {}

If you want to Send a reference, the underlying has to be Sync, otherwise it's not safe.

@diondokter
Copy link
Copy Markdown
Member

This PR is llm generated, right? Well it lied to you. Tests didn't pass

@msumme
Copy link
Copy Markdown
Author

msumme commented Apr 14, 2026

@diondokter yeah, I did use an LLM but verified cargo test succeeded (even now). I didn't notice the CI til this morning. I'll take a look.

…Send check

- Add Send + Sync bounds to the PostcardValue blanket impl's where clause
  so types using postcard via the Value trait satisfy the new supertraits.
- Extend the compile-time Send check to also cover fetch_item.
- Remove trailing blank line flagged by rustfmt.
@msumme
Copy link
Copy Markdown
Author

msumme commented Apr 14, 2026

Oh - I see now. CI doesn't automatically run! That explains why I didn't see that yesterday :)

@msumme
Copy link
Copy Markdown
Author

msumme commented Apr 15, 2026

@diondokter I ran all the stuff in CI locally, and this works on my laptop.

I tried a few variations that didn't add + Sync by adding the +Send bound elsewhere, and could not find one that would pass the test.

@diondokter
Copy link
Copy Markdown
Member

diondokter commented Apr 16, 2026

Thanks yeah. I'm thinking about it. I'm not pumped to add the Sync bound.
To me it's not unreasonable to want to impl Value for something that contains a refcell or a pointer.

The choice is: Do I make the Value trait more of a PITA to implement or do I limit how this crate can be used.

And so I need some time to think about it

@msumme
Copy link
Copy Markdown
Author

msumme commented Apr 16, 2026

I did think of 2 more options. They're in subsequent commits.

The first is adding the bounds to the call site. e8475e8

The second is adding a secondary function for store_item_local, which explicitly handles things that aren't Send + Sync. There might be a more elegant way to avoid duplication than the macro. 5dd764c

This keeps optionality, and minimally constrains types.

Interested to hear what you think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

store_item_inner's &dyn Value makes futures !Send

2 participants