into-owned 0.2.0

Provides a trait for associating a type with its owned variant
Documentation
// Copyright 2020 Koichi Kitahara
//
// Licensed under either of Apache License, Version 2.0:
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//
// or MIT license:
//
//   Permission is hereby granted, free of charge, to any person obtaining a
//   copy of this software and associated documentation files (the "Software"),
//   to deal in the Software without restriction, including without limitation
//   the rights to use, copy, modify, merge, publish, distribute, sublicense,
//   and/or sell copies of the Software, and to permit persons to whom the
//   Software is furnished to do so, subject to the following conditions:
//
//   The above copyright notice and this permission notice shall be included in
//   all copies or substantial portions of the Software.
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//   DEALINGS IN THE SOFTWARE.
//
// at your option.

//! Provides two kinds of clone-on-write smart pointers
//! based on [`IntoOwned`] instead of `std::borrow::ToOwned`.
//!
//! [`Gyu`] ([牛]: cow) is similar to `std::borrow::Cow`.
//! It holds an owned value or an immutably borrowed reference.
//! [`GyuMut`] (not GyuNyu [牛乳]: cow's milk) can hold a mutably borrowed reference
//! in addition to an owned value or an immutably borrowed reference.
//!
//! This module is highly experimental.
//! Most parts are subject to change.
//! Especially, more traits will be implemented for both [`Gyu`] and [`GyuMut`].
//!
//! [`IntoOwned`]: trait.IntoOwned.html
//! [`Gyu`]: enum.Gyu.html
//! [`GyuMut`]: enum.GyuMut.html
//! [牛]: https://en.wiktionary.org/wiki/牛
//! [牛乳]: https://en.wiktionary.org/wiki/牛乳

use super::IntoOwned;
use core::marker::PhantomData;

pub enum Gyu<'a, T>
where
    T: 'a + IntoOwned,
{
    Owned(OwnedInner<T>),
    Borrowed(BorrowedInner<'a, T>),
}

impl<T> From<T> for Gyu<'_, T>
where
    T: IntoOwned,
{
    fn from(t: T) -> Self {
        if t.is_owned() {
            Gyu::Owned(OwnedInner(t.into_owned()))
        } else {
            Gyu::Borrowed(BorrowedInner((t, PhantomData)))
        }
    }
}

pub enum GyuMut<'a, T>
where
    T: 'a + IntoOwned,
{
    Owned(OwnedInner<T>),
    Borrowed(BorrowedInner<'a, T>),
    MutBorrowed(MutBorrowedInner<'a, T>),
}

impl<T> From<T> for GyuMut<'_, T>
where
    T: IntoOwned,
{
    fn from(mut t: T) -> Self {
        if t.is_owned() {
            GyuMut::Owned(OwnedInner(t.into_owned()))
        } else if let Some(_) = t.try_as_mut() {
            GyuMut::MutBorrowed(MutBorrowedInner((t, PhantomData)))
        } else {
            GyuMut::Borrowed(BorrowedInner((t, PhantomData)))
        }
    }
}

pub struct OwnedInner<T>(T::Owned)
where
    T: IntoOwned;

pub struct BorrowedInner<'a, T>((T, PhantomData<&'a T::Owned>))
where
    T: 'a + IntoOwned;

pub struct MutBorrowedInner<'a, T>((T, PhantomData<&'a mut T::Owned>))
where
    T: 'a + IntoOwned;