Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 094b1cf

Browse files
max-sixtyclaude
andauthored
Revert Arc→Rc change, restore Send + Sync on Settings (#893)
The Arc→Rc change (#873) and Send+Sync removal (#874) were semver-breaking — they removed auto-trait impls from `Settings`, `Redactions`, `Redaction`, and `SettingsBindDropGuard`. This broke downstream crates like [cedar-policy](cedar-policy/cedar-spec#917) that depend on `Send + Sync`. This reverts to `Arc` and restores `Send + Sync` bounds on `Redaction` and `dynamic_redaction()`. Also adds `Send + Sync` to the `Comparator` trait (new in 1.47.0) since `Arc<ActualSettings>` requires it. A compile-time assertion prevents future regressions. TODOs mark the `Arc` usage and `Comparator` bounds as candidates for removal in the next breaking change. Thanks to @john-h-kastner-aws for reporting in #873 (comment). > _This was written by Claude Code on behalf of @max-sixty_ Co-authored-by: Claude <[email protected]>
1 parent 65a5233 commit 094b1cf

3 files changed

Lines changed: 30 additions & 13 deletions

File tree

insta/src/comparator.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ use crate::snapshot::{Snapshot, SnapshotContents, TextSnapshotKind};
1717
///
1818
/// This trait requires `'static` so that implementing structs can be stored in
1919
/// [`crate::settings::Settings`].
20-
pub trait Comparator: 'static {
20+
// TODO: `Send + Sync` is required because `Settings` currently uses `Arc`
21+
// internally. Consider removing these bounds if `Settings` switches to `Rc`
22+
// in the next breaking change.
23+
pub trait Comparator: Send + Sync + 'static {
2124
/// Returns `true` if the contents of `reference` and `test` match.
2225
///
2326
/// This is the standard comparison used by [`assert_snapshot!`].

insta/src/redaction.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub enum Redaction {
5454
/// Static redaction with new content.
5555
Static(Content),
5656
/// Redaction with new content.
57-
Dynamic(Box<dyn Fn(Content, ContentPath<'_>) -> Content>),
57+
Dynamic(Box<dyn Fn(Content, ContentPath<'_>) -> Content + Sync + Send>),
5858
}
5959

6060
macro_rules! impl_from {
@@ -127,7 +127,7 @@ impl<'a> From<&'a [u8]> for Redaction {
127127
pub fn dynamic_redaction<I, F>(func: F) -> Redaction
128128
where
129129
I: Into<Content>,
130-
F: Fn(Content, ContentPath<'_>) -> I + 'static,
130+
F: Fn(Content, ContentPath<'_>) -> I + Send + Sync + 'static,
131131
{
132132
Redaction::Dynamic(Box::new(move |c, p| func(c, p).into()))
133133
}

insta/src/settings.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::future::Future;
55
use std::mem;
66
use std::path::{Path, PathBuf};
77
use std::pin::Pin;
8-
use std::rc::Rc;
8+
use std::sync::Arc;
99
use std::task::{Context, Poll};
1010

1111
use crate::comparator::Comparator;
@@ -23,15 +23,15 @@ thread_local!(static CURRENT_SETTINGS: RefCell<Settings> = RefCell::new(Settings
2323
#[cfg(feature = "redactions")]
2424
#[cfg_attr(docsrs, doc(cfg(feature = "redactions")))]
2525
#[derive(Clone, Default)]
26-
pub struct Redactions(Vec<(Selector<'static>, Rc<Redaction>)>);
26+
pub struct Redactions(Vec<(Selector<'static>, Arc<Redaction>)>);
2727

2828
#[cfg(feature = "redactions")]
2929
impl<'a> From<Vec<(&'a str, Redaction)>> for Redactions {
3030
fn from(value: Vec<(&'a str, Redaction)>) -> Redactions {
3131
Redactions(
3232
value
3333
.into_iter()
34-
.map(|x| (Selector::parse(x.0).unwrap().make_static(), Rc::new(x.1)))
34+
.map(|x| (Selector::parse(x.0).unwrap().make_static(), Arc::new(x.1)))
3535
.collect(),
3636
)
3737
}
@@ -188,13 +188,17 @@ impl ActualSettings {
188188
/// ```
189189
#[derive(Clone)]
190190
pub struct Settings {
191-
inner: Rc<ActualSettings>,
191+
// TODO: consider switching to `Rc` in the next breaking change — `Settings`
192+
// are stored in thread-local storage and never cross thread boundaries, so
193+
// `Arc` is unnecessary. Removing it would also let us drop the `Send + Sync`
194+
// bounds on `Redaction` and `Comparator`.
195+
inner: Arc<ActualSettings>,
192196
}
193197

194198
impl Default for Settings {
195199
fn default() -> Settings {
196200
Settings {
197-
inner: Rc::new(ActualSettings {
201+
inner: Arc::new(ActualSettings {
198202
sort_maps: false,
199203
snapshot_path: "snapshots".into(),
200204
snapshot_suffix: "".into(),
@@ -232,7 +236,7 @@ impl Settings {
232236
/// Internal helper for macros
233237
#[doc(hidden)]
234238
pub fn _private_inner_mut(&mut self) -> &mut ActualSettings {
235-
Rc::make_mut(&mut self.inner)
239+
Arc::make_mut(&mut self.inner)
236240
}
237241

238242
/// Enables forceful sorting of maps before serialization.
@@ -435,7 +439,7 @@ impl Settings {
435439
fn add_redaction_impl(&mut self, selector: &str, replacement: Redaction) {
436440
self._private_inner_mut().redactions.0.push((
437441
Selector::parse(selector).unwrap().make_static(),
438-
Rc::new(replacement),
442+
Arc::new(replacement),
439443
));
440444
}
441445

@@ -451,7 +455,7 @@ impl Settings {
451455
pub fn add_dynamic_redaction<I, F>(&mut self, selector: &str, func: F)
452456
where
453457
I: Into<Content>,
454-
F: Fn(Content, ContentPath<'_>) -> I + 'static,
458+
F: Fn(Content, ContentPath<'_>) -> I + Send + Sync + 'static,
455459
{
456460
self.add_redaction(selector, dynamic_redaction(func));
457461
}
@@ -584,7 +588,7 @@ impl Settings {
584588
/// ```
585589
pub fn bind_async<F: Future<Output = T>, T>(&self, future: F) -> impl Future<Output = T> {
586590
struct BindingFuture<F> {
587-
settings: Rc<ActualSettings>,
591+
settings: Arc<ActualSettings>,
588592
future: F,
589593
}
590594

@@ -660,7 +664,7 @@ impl Settings {
660664
/// This is to ensure tests under async runtimes like `tokio` don't show unexpected results
661665
#[must_use = "The guard is immediately dropped so binding has no effect. Use `let _guard = ...` to bind it."]
662666
pub struct SettingsBindDropGuard(
663-
Option<Rc<ActualSettings>>,
667+
Option<Arc<ActualSettings>>,
664668
/// A ZST that is not [`Send`] but is [`Sync`]
665669
///
666670
/// This is necessary due to the lack of stable [negative impls](https://github.com/rust-lang/rust/issues/68318).
@@ -677,3 +681,13 @@ impl Drop for SettingsBindDropGuard {
677681
})
678682
}
679683
}
684+
685+
// Prevent accidental removal of Send/Sync (which is a semver-breaking change).
686+
const _: () = {
687+
fn _assert_send_sync<T: Send + Sync>() {}
688+
fn _assert() {
689+
_assert_send_sync::<Settings>();
690+
#[cfg(feature = "redactions")]
691+
_assert_send_sync::<Redactions>();
692+
}
693+
};

0 commit comments

Comments
 (0)