Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
libcore: add borrow module
Following [the collections reform
RFC](rust-lang/rfcs#235),
this commit adds a new `borrow` module to libcore.

The module contains traits for borrowing data (`BorrowFrom` and
`BorrowFromMut`),
generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).
  • Loading branch information
aturon committed Nov 17, 2014
commit 4ab22355d4d186d5eec52be0f980034685411d04
11 changes: 11 additions & 0 deletions src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -647,6 +648,16 @@ impl<T> SliceAllocPrelude<T> for [T] {
}
}

#[unstable = "trait is unstable"]
impl<T> BorrowFrom<Vec<T>> for [T] {
fn borrow_from(owned: &Vec<T>) -> &[T] { owned[] }
}

#[unstable = "trait is unstable"]
impl<T> BorrowFromMut<Vec<T>> for [T] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these be in vec.rs? Genuinely unsure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the BorrowFrom and BorrowFromMut traits are in libcore, they cannot implement for Vec there. Sincce these implementations can't be anywhere else, surely this is the right place?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They could be in the vec module in libcollections. I put them here because they are being applied to the slice type, and I feel like putting impls in the module defining their Self type is a good default.

fn borrow_from_mut(owned: &mut Vec<T>) -> &mut [T] { owned[mut] }
}

/// Unsafe operations
pub mod raw {
pub use core::slice::raw::{buf_as_slice, mut_buf_as_slice};
Expand Down
7 changes: 6 additions & 1 deletion src/libcollections/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -604,6 +604,11 @@ impl<'a> fmt::Show for MaybeOwned<'a> {
}
}

#[unstable = "trait is unstable"]
impl BorrowFrom<String> 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};
Expand Down
126 changes: 126 additions & 0 deletions src/libcore/borrow.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T>` 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<U>`, then `&T` can be borrowed from `&U`. A given
//! type can be borrowed as multiple different types. In particular, `Vec<T>:
//! BorrowFrom<Vec<T>>` and `[T]: BorrowFrom<Vec<T>>`.
//!
//! # 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<Sized? Owned> for Sized? {
/// Immutably borrow from an owned value.
fn borrow_from(owned: &Owned) -> &Self;
}

/// A trait for mutably borrowing data.
pub trait BorrowFromMut<Sized? Owned> for Sized? : BorrowFrom<Owned> {
/// Mutably borrow from an owned value.
fn borrow_from_mut(owned: &mut Owned) -> &mut Self;
}

impl<Sized? T> BorrowFrom<T> for T {
fn borrow_from(owned: &T) -> &T { owned }
}

impl<Sized? T> BorrowFromMut<T> 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<Owned> for Sized?: BorrowFrom<Owned> {
/// Create owned data from borrowed data, usually by copying.
fn to_owned(&self) -> Owned;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why to_owned must takes a reference?

I think that HashMap::entry() can take a ToOwned<K> as key, and create a owned object if needed. But to have that to work, we should have to_owned taking self to allow T: ToOwned<T> to just move.

Example: http://is.gd/YORUei

I didn't tried to modify this pull request with this change, so maybe there is problem in Cow with this change.

}

impl<T> ToOwned<T> 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<T> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want people to be able to match on the internals of this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I debated making this a newtype. That's probably the more conservative thing to do, but then we'd need to separately expose constructors. Either way is fine by me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... unsure. I feel like newtyping is "the right thing", but I dunno. It's unstable so I think we can leave it like this for now, and revisit this for stabilization.

/// Borrowed data.
Borrowed(&'a B),

/// Owned data.
Owned(T)
}

impl<'a, T, B> Cow<'a, T, B> where B: ToOwned<T> {
/// 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<B> for Cow<'a, T, B> where B: ToOwned<T> {
fn deref(&self) -> &B {
match *self {
Borrowed(borrowed) => borrowed,
Owned(ref owned) => BorrowFrom::borrow_from(owned)
}
}
}
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down