Crate bos[][src]

Expand description

This crate provides flexible Borrowed, Owned or Shared (B.O.S.) smart pointers. They are like std’s Cow but with additonal Arc and Rc variants. Unlike std’s Cow, they can also be used with types that don’t implement Clone or ToOwned.

The bos smart pointers allow you to:

  • share data efficiently
  • decide ownership at runtime
  • avoid cloning the data until it becomes necessary

“A” stands for “atomic”

For example Abos implements Send and Sync but does not have a Rc variant.

Bos does not implement Send or Sync but does have a Rc variant.

AbosStr and BosStr types

Abos and Bos are often used with str or similar types. Feel free to have a look at our handy type aliases below.

features

Enable additional features or optional dependencies by adding the following to your Cargo.toml, replacing “x.y” with the version you want.

[dependencies]
bos = { version = "x.y", features = ["serde", "lifetime"] }

Examples

use std::sync::Arc;
use bos::AbosStr;

// No need to allocate memory for a &'static str
let title = AbosStr::Borrowed("Dune");

// The author's name shouldn't be too long.
// So we can just store it in a normal String.
let author = AbosStr::Owned(read_file("dune/author.txt"));

// A whole book is really long.
// And we want to share this string with multiple threads.
// So it would be efficient to store in an Arc,
// since cloning the Arc does not clone the String data inside of it.
let book_text = AbosStr::Arc(Arc::new(read_file("dune/book.txt")));

// We can store a &str, String and Arc<String> inside the same Vec
// because we are using the AbosStr enum.
let book_infos: Vec<AbosStr> = vec![title, author, book_text];

fn read_file(path: &str) -> String {
    // ...
}

This example shows how to use Abos in a struct using the lifetime and serde crates.

use assert_matches::assert_matches;
use bos::AbosStr;
use lifetime::{IntoStatic, ToBorrowed};
use serde::{Deserialize, Deserializer};
use std::sync::Arc;

#[derive(IntoStatic, ToBorrowed, Deserialize)]
struct Header<'a> {
    name: AbosStr<'a>,

    #[serde(deserialize_with = "arc_string_if_long")]
    value: AbosStr<'a>,
}

fn arc_string_if_long<'b, 'de, D>(d: D) -> Result<AbosStr<'b>, D::Error>
where
    D: Deserializer<'de>,
{
    let s: String = Deserialize::deserialize(d)?;
    Ok(if s.len() < 10 { // 10 is way too small. Try something like 1000 in your code.
        AbosStr::Owned(s)
    } else {
        AbosStr::Arc(Arc::new(s))
    })
}

// Let's pretend this JSON String came over the network.
let header_json =
    String::from(r#"{ "name":"content", "value":"text/html; charset=UTF-8" }"#);
let content: Header<'static> = serde_json::from_str(&header_json)?;

let mut content_type: Header<'_> = content.to_borrowed();
content_type.name += "-type"; // creates a new String

// content header has not moved
assert_eq!(content.name, "content");
assert_eq!(content_type.name, "content-type");
assert_matches!(&content_type.value, AbosStr::BorrowedArc(arc) if Arc::strong_count(arc) == 1);

let static_content_type: Header<'static> = content_type.into_static();
assert_eq!(static_content_type.value, "text/html; charset=UTF-8");
assert_matches!(&static_content_type.value, AbosStr::Arc(arc) if Arc::strong_count(arc) == 2);

Enums

Atomic Borrowed, Owned or Shared smart pointer.

Borrowed, Owned or Shared smart pointer.

Type Definitions

Atomic Borrowed, Owned or Shared heap allocating smart pointer.

Atomic Borrowed, Owned or Shared str smart pointer.

Atomic Borrowed, Owned or Shared smart pointer for types implementing the ToOwned (T.O.) trait.

Atomic Borrowed, Owned or Shared Vec smart pointer.

Borrowed, Owned or Shared heap allocating smart pointer.

Borrowed, Owned or Shared str smart pointer.

Borrowed, Owned or Shared smart pointer for types implementing the ToOwned (T.O.) trait.

Borrowed, Owned or Shared Vec smart pointer.