diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 000c3e08c677b..132a07af6b67b 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -89,6 +89,7 @@ use self::Direction::*; use alloc::boxed::Box; +use core::borrow::{BorrowFrom, BorrowFromMut}; use core::cmp; use core::kinds::Sized; use core::mem::size_of; @@ -647,6 +648,16 @@ impl SliceAllocPrelude for [T] { } } +#[unstable = "trait is unstable"] +impl BorrowFrom> for [T] { + fn borrow_from(owned: &Vec) -> &[T] { owned[] } +} + +#[unstable = "trait is unstable"] +impl BorrowFromMut> for [T] { + fn borrow_from_mut(owned: &mut Vec) -> &mut [T] { owned[mut] } +} + /// Unsafe operations pub mod raw { pub use core::slice::raw::{buf_as_slice, mut_buf_as_slice}; diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index ae8e92fc6cb9d..9ae009d8f6a59 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -54,7 +54,7 @@ pub use self::MaybeOwned::*; use self::RecompositionState::*; use self::DecompositionType::*; - +use core::borrow::BorrowFrom; use core::default::Default; use core::fmt; use core::cmp; @@ -604,6 +604,11 @@ impl<'a> fmt::Show for MaybeOwned<'a> { } } +#[unstable = "trait is unstable"] +impl BorrowFrom for str { + fn borrow_from(owned: &String) -> &str { owned[] } +} + /// Unsafe string operations. pub mod raw { pub use core::str::raw::{from_utf8, c_str_to_static_slice, slice_bytes}; diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs new file mode 100644 index 0000000000000..34cf55334aef3 --- /dev/null +++ b/src/libcore/borrow.rs @@ -0,0 +1,126 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A module for working with borrowed data. +//! +//! # The `BorrowFrom` traits +//! +//! In general, there may be several ways to "borrow" a piece of data. The +//! typical ways of borrowing a type `T` are `&T` (a shared borrow) and `&mut T` +//! (a mutable borrow). But types like `Vec` provide additional kinds of +//! borrows: the borrowed slices `&[T]` and `&mut [T]`. +//! +//! When writing generic code, it is often desirable to abstract over all ways +//! of borrowing data from a given type. That is the role of the `BorrowFrom` +//! trait: if `T: BorrowFrom`, then `&T` can be borrowed from `&U`. A given +//! type can be borrowed as multiple different types. In particular, `Vec: +//! BorrowFrom>` and `[T]: BorrowFrom>`. +//! +//! # The `ToOwned` trait +//! +//! Some types make it possible to go from borrowed to owned, usually by +//! implementing the `Clone` trait. But `Clone` works only for going from `&T` +//! to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data +//! from any borrow of a given type. +//! +//! # The `Cow` (clone-on-write) type +//! +//! The type `Cow` is a smart pointer providing clone-on-write functionality: it +//! can enclose and provide immutable access to borrowed data, and clone the +//! data lazily when mutation or ownership is required. The type is designed to +//! work with general borrowed data via the `BorrowFrom` trait. +//! +//! `Cow` implements both `Deref` and `DerefMut`, which means that you can call +//! methods directly on the data it encloses. The first time a mutable reference +//! is required, the data will be cloned (via `to_owned`) if it is not +//! already owned. + +#![unstable = "recently added as part of collections reform"] + +use clone::Clone; +use kinds::Sized; +use ops::Deref; + +/// A trait for borrowing data. +pub trait BorrowFrom for Sized? { + /// Immutably borrow from an owned value. + fn borrow_from(owned: &Owned) -> &Self; +} + +/// A trait for mutably borrowing data. +pub trait BorrowFromMut for Sized? : BorrowFrom { + /// Mutably borrow from an owned value. + fn borrow_from_mut(owned: &mut Owned) -> &mut Self; +} + +impl BorrowFrom for T { + fn borrow_from(owned: &T) -> &T { owned } +} + +impl BorrowFromMut for T { + fn borrow_from_mut(owned: &mut T) -> &mut T { owned } +} + +impl BorrowFrom<&'static str> for str { + fn borrow_from<'a>(owned: &'a &'static str) -> &'a str { &**owned } +} + +/// A generalization of Clone to borrowed data. +pub trait ToOwned for Sized?: BorrowFrom { + /// Create owned data from borrowed data, usually by copying. + fn to_owned(&self) -> Owned; +} + +impl ToOwned for T where T: Clone { + fn to_owned(&self) -> T { self.clone() } +} + +/// A clone-on-write smart pointer. +pub enum Cow<'a, T, B: 'a> where B: ToOwned { + /// Borrowed data. + Borrowed(&'a B), + + /// Owned data. + Owned(T) +} + +impl<'a, T, B> Cow<'a, T, B> where B: ToOwned { + /// Acquire a mutable reference to the owned form of the data. + /// + /// Copies the data if it is not already owned. + pub fn to_mut(&mut self) -> &mut T { + match *self { + Borrowed(borrowed) => { + *self = Owned(borrowed.to_owned()); + self.to_mut() + } + Owned(ref mut owned) => owned + } + } + + /// Extract the owned data. + /// + /// Copies the data if it is not already owned. + pub fn into_owned(self) -> T { + match self { + Borrowed(borrowed) => borrowed.to_owned(), + Owned(owned) => owned + } + } +} + +impl<'a, T, B> Deref for Cow<'a, T, B> where B: ToOwned { + fn deref(&self) -> &B { + match *self { + Borrowed(borrowed) => borrowed, + Owned(ref owned) => BorrowFrom::borrow_from(owned) + } + } +} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9689f7cdd7114..5e3c74477d15c 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -108,6 +108,7 @@ pub mod default; pub mod any; pub mod atomic; pub mod bool; +pub mod borrow; pub mod cell; pub mod char; pub mod panicking; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 612613134d448..7f2a4c7e36569 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -141,6 +141,7 @@ extern crate rustrt; pub use core::any; pub use core::bool; +pub use core::borrow; pub use core::cell; pub use core::clone; #[cfg(not(test))] pub use core::cmp;