bos 0.3.1

Flexible Borrowed, Owned or Shared (B.O.S.) smart pointers. Like std's Cow but with Rc/Arc and without the ToOwned requirement.
Documentation
/*!
This crate provides flexible
**B**orrowed, **O**wned or **S**hared (B.O.S.) smart pointers.
They are like std's [`Cow`][std::borrow::Cow]
but with additonal [`Arc`][std::sync::Arc]
and [`Rc`][std::rc::Rc] variants.
Unlike std's [`Cow`][std::borrow::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`][std::rc::Rc] variant.

[`Bos`] does *not* implement [`Send`] or [`Sync`]
but does have a [`Rc`][std::rc::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](#types) below.

# features

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

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

# Examples

```rust
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 {
    // ...
# String::new()
}
```
*/
#![cfg_attr(
    all(feature = "lifetime", feature = "serde"),
    doc = r##"
This example shows how to use [`Abos`] in a struct
using the [`lifetime`] and [`serde`] crates.
```rust
# fn main() -> Result<(), Box<dyn std::error::Error>> {
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);
# Ok(()) }
```
"##
)]
#![forbid(unsafe_code)]

mod abos;
mod bos;

#[cfg(feature = "serde")]
mod serde_support;

pub use self::abos::Abos;
pub use self::bos::Bos;

/// **A**tomic **B**orrowed, **O**wned or **S**hared smart pointer for types implementing the [`ToOwned`] (**T**.**O**.) trait.
pub type AbosTo<'b, B> = Abos<'b, B, <B as ToOwned>::Owned, <B as ToOwned>::Owned>;

/// **B**orrowed, **O**wned or **S**hared smart pointer for types implementing the [`ToOwned`] (**T**.**O**.) trait.
pub type BosTo<'b, B> = Bos<'b, B, <B as ToOwned>::Owned, <B as ToOwned>::Owned>;

/// **A**tomic **B**orrowed, **O**wned or **S**hared heap allocating smart pointer.
pub type AbosBox<'b, T> = Abos<'b, T, Box<T>, T>;

/// **B**orrowed, **O**wned or **S**hared heap allocating smart pointer.
pub type BosBox<'b, T> = Bos<'b, T, Box<T>, T>;

/// **A**tomic **B**orrowed, **O**wned or **S**hared [`str`] smart pointer.
pub type AbosStr<'b> = AbosTo<'b, str>;

/// **B**orrowed, **O**wned or **S**hared [`str`] smart pointer.
pub type BosStr<'b> = BosTo<'b, str>;

/// **A**tomic **B**orrowed, **O**wned or **S**hared [`Vec`] smart pointer.
pub type AbosVec<'b, T> = Abos<'b, [T], Vec<T>>;

/// **B**orrowed, **O**wned or **S**hared [`Vec`] smart pointer.
pub type BosVec<'b, T> = Bos<'b, [T], Vec<T>>;