Does anyone know of techniques to specialize on Copy specifically in stable Rust? I am currently using the typeid crate to test whether a type is one of a known set of Copy types that are likely to be used with my library. Reading the Rust issues I have seen mentions of some libraries using hacks which rely on the fact that some standard library methods won't call the Clone impl for a type if it also implements Copy, but this is a cause for sadness amongst the stdlib maintainers.
It looks like the typeid approach of specializing for a few concrete types (mainly primitive int and float types) with no lifetimes involved should still be OK.
That said, what are you hoping to do with the Copy -ness? Sometimes, for optimizations, just checking needs_drop::<T>() can be sufficient.
This is for various data copying operations in an ndarray-like library, where I'm copying chunks out of a source buffer into an uninitialized destination. [MaybeUninit<T>]::write_clone_of_slice would be useful for some of these when stabilized, if it reliably generated a memcpy for Copy types. There are also operations such as transposes, where an optimized implementation will load a tile of data into registers and shuffle it around, provided the type has a supported bit-width and is Copy.
For concrete types, yes. But be careful about expanding this logic to some generic specialization on the assumption that : 'static means "no subtyping".
Rust does have subtyping between distinct : 'statictypes today, for example fn(&str) is a subtype of fn(&'static str).[1] If your specialization assumes subtyping can't occur, e.g. that a specialization for a subtype can never "switch" to the potentially unspecialized implementation of its supertype, unsoundness can occur. So you really do need "no lifetimes"[2] and not just "all 'static" to know there is no subtyping today, and AFAIK there is no way to generically require "no lifetimes".[3]
Additionally, the surface area of such subtype relationships may expand if we get non-lifetime binders (for<T: Bound> fn(T)), as that could introduce subtyping that does not involve lifetimes at all.
But if you're sticking to concrete types, the sub/super type relationships should remain more obvious. When using generics, introducing your own invariance can remove the possibility of subtyping instead.
And similarly for higher-ranked dyn Trait types, so this is not a function pointer specific property. ↩︎