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§
Type Aliases§
- AbosBox
- Atomic Borrowed, Owned or Shared heap allocating smart pointer.
- AbosStr
- Atomic Borrowed, Owned or Shared
str
smart pointer. - AbosTo
- Atomic Borrowed, Owned or Shared smart pointer for types implementing the
ToOwned
(T.O.) trait. - AbosVec
- Atomic Borrowed, Owned or Shared
Vec
smart pointer. - BosBox
- Borrowed, Owned or Shared heap allocating smart pointer.
- BosStr
- Borrowed, Owned or Shared
str
smart pointer. - BosTo
- Borrowed, Owned or Shared smart pointer for types implementing the
ToOwned
(T.O.) trait. - BosVec
- Borrowed, Owned or Shared
Vec
smart pointer.