// Is this idiomatic?
#[test]
const fn test_if_unit_arc_is_sync1() {
const fn takes_sync<T: Sync>() {}
takes_sync::<std::sync::Arc::<()>>();
}
// Or is this better?
#[allow(dead_code)]
const fn test_if_unit_arc_is_sync2() {
const fn takes_sync<T: Sync>() {}
takes_sync::<std::sync::Arc::<()>>();
// This test doesn't actually run, but it will result
// in a compiler error if we uncomment this:
//takes_sync::<std::rc::Rc<()>>();
}
I'd say that this is a compile-time property, so deferring it to a #[test] is not the best idea. After all, tests are not always compiled, so if you forget to run your tests, you might end up pushing/publishing code that's not working as intended.
But I think it would be okay to only compile it during testing. I don't see a need to compile this during normal builds. It would only make building slower.
And if I put it in #[cfg(test)], then I'm still unsure whether it should be a #[test].
But if there's some more idiomatic approach, I'm happy to hear about them. (Also happy to hear more comments on whether I should mark the functions #[test] and/or include them in a test module at all.)
I just noticed they do similar as tokio does (source).
One of the nice things about tests is that some can run while others fail. If your tests do not compile, then none of them will run.
Personally, I don't think you need to test whether something implements Sync (or any trait for that matter)
If it needs to implement Sync, then you will have code that requires it to be Sync and that will not compile.
There's not much benefit from adding an additional type constraint that isn't reflected elsewhere in your codebase
If I include it in a #[cfg(test)] section, then the failure lets me at least build the crate.
No not really, it might only happen once someone uses a type in a multithreaded context.
Well, maybe the benefit is low, though sometimes whether a type is Send or Sync is determined indirectly. I would like to ensure that the overall result of my unsafe impl Send and unsafe impl Sync implementations result in the correct Sendness and Syncness for all exported types and to not get any surprises.
This is definitely not true. What if it's a public API type? I am creating a database abstraction layer, and since databases are in general used in a highly concurrent fashion, the main entry point of my library is intended to be used in a multi-threaded environment. However:
it's not used by anything else in my code, because it's the entry point of the public API, so nothing else in my own code relies on it.
it contains raw pointers (due to FFI), which would make it !Send + !Sync by default, so I have to explicitly make it Send + Sync. I thus have to ensure that they implement these two traits, otherwise I might delete the unsafe impls accidentally during a refactor, for example.
Fair point, OP doesn't really specify whether they're making a library.
AFAIK you don't really need to assert traits unless you're exposing a public interface.
Still, though, the tests you're writing for the library should have some usage that requires Sync/Send. The static_assertions library you linked seems like a good way to double check though
I think the #[test] pattern is fine, and I've used it.
If it's testing your implementation, rather than being some kind of contract that user code could break at any time, then it doesn't have to be asserted every time the code is compiled.
Having this in tests and labelled as a test helps future maintainers of the code understand what it's for.