into-owned 0.3.0-alpha.3

This crate has been merged into as-is crate and is no longer developed by the current author.
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.

#![cfg_attr(not(feature = "std"), no_std)]
#![doc(html_root_url = "https://docs.rs/into-owned/0.3.0-alpha.2")]

//! This crate provides a trait [`IntoOwned`] and three enums [`Is<'a, T>`], [`Gyu<'a, T>`], and [`GyuMut<'a, T>`].
//!
//! [`IntoOwned`] associates a type with its owned variant.
//! In this experimental version, [`IntoOwned`] is implemented only for primitive numeric types
//! (`i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `f32`, and `f64`)
//! and their references.
//!
//! [`Is<'a, T>`], [`Gyu<'a, T>`], and [`GyuMut<'a, T>`] are clone-on-write smart pointers similar to [`Cow<'a, B>`].
//! These can be constructed from a type which is [`IntoOwned`].
//! See each documentation for more.
//!
//! [`IntoOwned`]: trait.IntoOwned.html
//! [`Is<'a, T>`]: enum.Is.html
//! [`Gyu<'a, T>`]: enum.Gyu.html
//! [`GyuMut<'a, T>`]: enum.GyuMut.html
//! [`Cow<'a, B>`]: https://doc.rust-lang.org/std/convert/trait.Cow.html

mod gyu;
mod gyu_mut;
mod is;

pub use gyu::Gyu;
pub use gyu_mut::GyuMut;
pub use is::Is;

#[cfg(feature = "std")]
use std::borrow::{Borrow, Cow};

/// A trait for associating a type with its owned variant.
///
/// # Examples
///
/// Implementing the `IntoOwned` trait for an owned type is straighitforward.
/// Maybe a derive macro is supplied in future.
/// ```
/// use into_owned::{IntoOwned, Is};
///
/// struct A();
///
/// impl IntoOwned for A {
///     type Owned = Self;
///
///     fn as_is<'a>(self) -> Is<'a, Self::Owned> {
///         Is::Owned(self)
///     }
/// }
/// ```
/// Since there are blanket implementations for `&T` and `&mut T` where
/// `T: IntoOwned<Owned = T>`,
/// manually implementing `IntoOwned` for the owned type is sufficient in most cases.
pub trait IntoOwned
where
    Self: Sized,
{
    /// The owned type associated with `Self`.
    type Owned: Owned;

    /// Returns `self` as [`Is<'a, T>`] (`T` is `Self::Owned` here).
    ///
    /// This method is useful when `self` is used differently depending on
    /// its state: owned, (immutably) borrowed, or mutably borrowed.
    ///
    /// # Examples
    /// ```
    /// use into_owned::{IntoOwned, Is};
    ///
    /// // returns:
    /// // * `0` if `t` is an owned value
    /// // * `1` if `t` is an immutably borrowed reference
    /// // * `2` if `t` is a mutably borrowed reference
    /// fn a<T>(t: T) -> i8
    /// where T: IntoOwned
    /// {
    ///     match t.as_is() {
    ///         Is::Owned(x) => {
    ///             // here `x: T::Owned`
    ///             0
    ///         }
    ///         Is::Borrowed(x) => {
    ///             // here `x: &T::Owned`
    ///             1
    ///         }
    ///         Is::MutBorrowed(x) => {
    ///             // here `x: &mut T::Owned`
    ///             2
    ///         }
    ///     }
    /// }
    ///
    /// assert_eq!(a(1.0), 0);
    /// assert_eq!(a(&1.0), 1);
    /// assert_eq!(a(&mut 1.0), 2);
    /// ```
    ///
    /// In addition, [`Is<'a, T>`] has a functionality similar to [`Cow<'a, B>`].
    /// See its documentation for more.
    ///
    /// [`Is<'a, T>`]: enum.Is.html
    /// [`Cow<'a, B>`]: https://doc.rust-lang.org/std/convert/trait.Cow.html
    fn as_is<'a>(self) -> Is<'a, Self::Owned>
    where
        Self: 'a;

    /// Converts `self` into an owned value.
    ///
    /// If `Self` and `Self::Owned` are the same, usually it just returns `self`.
    /// If not, usually it returns an owned value by cloning.
    ///
    /// This method requires `Self::Owned` to be `Clone`.
    fn into_owned(self) -> Self::Owned
    where
        Self::Owned: Clone,
    {
        match self.as_is() {
            Is::Owned(t) => t,
            Is::Borrowed(t) => t.clone(),
            Is::MutBorrowed(t) => t.clone(),
        }
    }

    /// Converts `self` into [`Gyu<'a, T>`] (`T` is `Self::Owned` here).
    ///
    /// [`Gyu<'a, T>`] has a functionality similar to [`Is<'a, T>`].
    /// Unlike [`Is<'a, T>`], it cannot hold a mutably borrowed reference,
    /// and thus it is more similar to [`Cow<'a, B>`].
    /// See its documentation for more.
    ///
    /// [`Is<'a, T>`]: enum.Is.html
    /// [`Gyu<'a, T>`]: enum.Gyu.html
    /// [`Cow<'a, B>`]: https://doc.rust-lang.org/std/convert/trait.Cow.html
    fn into_gyu<'a>(self) -> Gyu<'a, Self::Owned>
    where
        Self: 'a,
    {
        match self.as_is() {
            Is::Owned(t) => Gyu::Owned(t),
            Is::Borrowed(t) => Gyu::Borrowed(t),
            Is::MutBorrowed(t) => Gyu::Borrowed(&*t),
        }
    }

    /// Converts `self` into [`GyuMut<'a, T>`] (`T` is `Self::Owned` here).
    /// It clones `self` if it is an immutably borrowed reference.
    ///
    /// [`GyuMut<'a, T>`] has a functionality similar to [`Is<'a, T>`].
    /// Unlike [`Is<'a, T>`], it cannot hold a immutably borrowed reference.
    /// [`GyuMut<'a, T>`] implements more traits which require mutablity.
    /// See its documentation for more.
    ///
    /// [`try_into_gyu_mut`]: #method.try_into_gyu_mut
    /// [`GyuMut<'a, T>`]: enum.GyuMut.html
    fn into_gyu_mut<'a>(self) -> GyuMut<'a, Self::Owned>
    where
        Self: 'a,
        Self::Owned: Clone,
    {
        match self.as_is() {
            Is::Owned(t) => GyuMut::Owned(t),
            Is::Borrowed(t) => GyuMut::Owned(t.clone()),
            Is::MutBorrowed(t) => GyuMut::MutBorrowed(t),
        }
    }

    /// Converts `self` into [`Cow<'a, B>`].
    ///
    /// This method is available if `std` feature is enabled (enabled by default).
    ///
    /// [`Cow<'a, B>`]: https://doc.rust-lang.org/std/convert/trait.Cow.html
    #[cfg(feature = "std")]
    fn into_cow<'a, B>(self) -> Cow<'a, B>
    where
        Self: 'a,
        Self::Owned: Borrow<B>,
        B: ToOwned<Owned = Self::Owned> + ?Sized,
    {
        match self.as_is() {
            Is::Owned(t) => Cow::Owned(t),
            Is::Borrowed(t) => Cow::Borrowed(t.borrow()),
            Is::MutBorrowed(t) => Cow::Borrowed((*t).borrow()),
        }
    }
}

impl<T> IntoOwned for &T
where
    T: Owned,
{
    type Owned = T;

    fn as_is<'a>(self) -> Is<'a, Self::Owned>
    where
        Self: 'a,
    {
        Is::Borrowed(self)
    }
}

impl<T> IntoOwned for &mut T
where
    T: Owned,
{
    type Owned = T;

    fn as_is<'a>(self) -> Is<'a, Self::Owned>
    where
        Self: 'a,
    {
        Is::MutBorrowed(self)
    }
}

macro_rules! impl_into_owned_for_owned_type {
    ($($T:ty),*) => {
        $(
            impl IntoOwned for $T {
                type Owned = Self;

                fn as_is<'a>(self) -> Is<'a, Self::Owned> {
                    Is::Owned(self)
                }
            }
        )*
    };
}

impl_into_owned_for_owned_type!(
    i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64
);

/// A trait for an owned type.
///
/// This trait is automatically implemented where `Self: `[`IntoOwned`]`<`[`Owned`]` = Self>`.
///
/// [`IntoOwned`]: trait.IntoOwned.html
/// [`Owned`]: trait.IntoOwned.html#associatedtype.Owned
pub trait Owned
where
    Self: IntoOwned<Owned = Self>,
{
}

impl<T> Owned for T where Self: IntoOwned<Owned = Self> {}