Using notation (H, ...T) from rfc 1935 (Tuple-Based Variadic Generics) to mean some non empty tuple with a first element of type H (head) and a rest equivalent to the tuple of type T (tail):
impl Send for () {}
impl<T, H> Send for (H, ...T) where T : Tuple + Send, H: Send {}
Similarily for structs if we imagine another automatic trait:
trait Struct {
type Details: Tuple;
}
impl<T> Send for T where T : Struct, T::Details : Send {}
where for example if we have struct Point { x: f64, y: f64}, we would have Point::Details == (f64, f64). Same kind of logic for enums, closures, etc
Correct but the implementation is automatically prevented by the compiler if your type contains at least one non-copiable component. To this respect this is as magical as Send or Sync.
Now suppose we have negative bounds we could encode this fact as:
impl Copy for () {}
impl<T, H> !Copy for (H, ...T) where H: !Copy, T : Copy {}
impl<T, H> !Copy for (H, ...T) where H: Copy, T : !Copy {}
impl<T, H> !Copy for (H, ...T) where H: !Copy, T : !Copy {}
impl<T> !Copy for T where T : Struct, T::Details : !Copy {}
Of course as such I’m replacing previous magical traits (Send, Copy, etc) by new ones (Tuple, Struct, etc) but I have the feeling this would be more natural and far more extensive (allowing users to define their own automatically implemented “structural” traits)