Understanding Borrow and ToOwned

In my case, it seems like I need a trait that allows me to go from the owned type to the (usual) borrowed type.

I finally ended up making my own type for that:

pub trait BorrowStorable
where
    Self: Sized + Borrow<Self::Stored> + Ord,
{
    type Stored: ?Sized + StorableWithOwned<Self>;
}

impl<T> BorrowStorable for T
where
    T: StorableWithOwned<T>,
{
    type Stored = Self;
}

impl<T> BorrowStorable for Vec<T>
where
    T: Ord,
    [T]: StorableWithOwned<Vec<T>>,
{
    type Stored = [T];
}

impl BorrowStorable for String {
    type Stored = str;
}

Which I can then use like this:

 unsafe impl<T1, T2> Storable for (T1, T2)
 where
-    T1: StorableWithOwned<T1> + StorableConstBytesLen,
-    T2: StorableWithOwned<T2>,
+    T1: BorrowStorable,
+    T2: BorrowStorable,
+    <T1 as BorrowStorable>::Stored: StorableConstBytesLen,
 {
-    const CONST_BYTES_LEN: bool = T2::CONST_BYTES_LEN;
+    const CONST_BYTES_LEN: bool = <T2 as BorrowStorable>::Stored::CONST_BYTES_LEN;
     type AlignedRef<'a> = Owned<Self>;
     type BytesRef<'a> = Vec<u8>
     where
         T1: 'a,
         T2: 'a;
     fn to_bytes(&self) -> Self::BytesRef<'_> {
-        let mut bytes = Vec::with_capacity(self.0.bytes_len() + self.1.bytes_len());
-        bytes.extend_from_slice(&self.0.to_bytes());
-        bytes.extend_from_slice(&self.1.to_bytes());
+        let mut bytes = Vec::with_capacity(self.0.borrow().bytes_len() + self.1.borrow().bytes_len());
+        bytes.extend_from_slice(&self.0.borrow().to_bytes());
+        bytes.extend_from_slice(&self.1.borrow().to_bytes());
         bytes
     }
     unsafe fn from_bytes_unchecked(bytes: &[u8]) -> Self::AlignedRef<'_> {
-        let v1: T1 = T1::owned_from_bytes_unchecked(&bytes[0..T1::BYTES_LEN]);
-        let v2: T2 = T2::owned_from_bytes_unchecked(&bytes[T1::BYTES_LEN..]);
+        let v1: T1 = <T1 as BorrowStorable>::Stored::owned_from_bytes_unchecked(&bytes[0..<T1 as BorrowStorable>::Stored::BYTES_LEN]);
+        let v2: T2 = <T2 as BorrowStorable>::Stored::owned_from_bytes_unchecked(&bytes[<T1 as BorrowStorable>::Stored::BYTES_LEN..]);
         Owned((v1, v2))
     }
 }

Such that even if Vec<u8> is not Storable (you're supposed to use [u8]), I still have a (u64, Vec<u8>) being Storable.

But not sure if all that makes sense. I'm still working on it. I just shared it here to point out what was my original go: Have a trait that serves as a type constructor which goes from String to str (where I could use Deref maybe?) but also from i32 to i32 (where I can't use Deref), i.e. from an owned type to the immutable borrowed type.

StorableWithOwned, I defined like this:

pub trait StorableWithOwned<T>: Storable {
    /// Converts from byte slice into (owned) `Self`
    unsafe fn owned_from_bytes_unchecked(bytes: &[u8]) -> T;
}

impl<T, O> StorableWithOwned<O> for T
where
    T: ?Sized + Storable,
    for<'a> <<T as Storable>::AlignedRef<'a> as PointerIntoOwned>::Owned: IsType<O>,
{
    unsafe fn owned_from_bytes_unchecked(bytes: &[u8]) -> O {
        Self::from_bytes_unchecked(bytes).into_owned().identity()
    }
}

trait IsType<T> {
    /// Returns value with its type being same as the type argument
    fn identity(self) -> T;
}

impl<T> IsType<T> for T {
    fn identity(self) -> T {
        self
    }
}

Btw, I wonder if my IsType helper trait is something that's also commonly needed in other contexts. It's very generic actually, but I suppose we don't have something like that in std?