shared_bytes 0.1.0-beta.4

Owned string and byte slices.
Documentation
use super::SharedStr;
use crate::SharedBytes;
use quickcheck::Arbitrary;
use std::{convert::identity, ops::Range, sync::Arc};

type Bounds = Range<usize>;

#[test]
fn qc_to_bytes_and_back() {
    quickcheck::quickcheck(test_to_bytes_and_back as fn(SharedStringFromVecFn, String, Bounds))
}

fn test_to_bytes_and_back(new: SharedStringFromVecFn, string: String, bounds: Bounds) {
    let shared_string = new
        .call(string)
        .try_slice_into(bounds)
        .unwrap_or_else(identity);
    let actual_bytes = SharedBytes::from(shared_string.clone());
    assert_eq!(actual_bytes, shared_string.as_bytes());
    let actual_string = SharedStr::from_utf8(actual_bytes).unwrap();
    assert_eq!(actual_string, shared_string);
}

#[test]
fn qc_try_slice_to_subset() {
    quickcheck::quickcheck(test_try_slice_to_subset as fn(SharedStringFromVecFn, String, Bounds))
}

fn test_try_slice_to_subset(new: SharedStringFromVecFn, string: String, bounds: Bounds) {
    let shared_string = new.call(string);
    let subset = match shared_string.get(bounds) {
        Some(x) => x,
        None => return,
    };
    let actual = shared_string
        .clone()
        .try_slice_into(shared_string.range_of_subset(subset))
        .unwrap();
    assert_eq!(actual, subset);
}

#[test]
fn try_slice_range() {
    for &new in SHARED_STRING_FROM_STATIC_FNS {
        let actual_1 = new("0123456").try_slice_into(2..6).unwrap();
        assert_eq!(actual_1, "2345");
        let actual_2 = actual_1.try_slice_into(1..3).unwrap();
        assert_eq!(actual_2, "34");
    }
}

#[test]
fn try_slice_range_to() {
    for &new in SHARED_STRING_FROM_STATIC_FNS {
        let actual_1 = new("0123456").try_slice_into(..6).unwrap();
        assert_eq!(actual_1, "012345");
        let actual_2 = actual_1.try_slice_into(..3).unwrap();
        assert_eq!(actual_2, "012");
    }
}

#[test]
fn try_slice_range_from() {
    for &new in SHARED_STRING_FROM_STATIC_FNS {
        let actual_1 = new("0123456").try_slice_into(3..).unwrap();
        assert_eq!(actual_1, "3456");
        let actual_2 = actual_1.try_slice_into(1..).unwrap();
        assert_eq!(actual_2, "456");
    }
}

#[test]
fn try_slice_inside_utf_8_char() {
    let string = "".to_owned();
    assert_eq!(string.as_bytes(), [226, 130, 172].as_slice());
    let shared_string = SharedStr::from(Arc::new(string.clone()));
    let actual_err = shared_string.try_slice_into(1..2).unwrap_err();
    assert_eq!(actual_err, string);
}

#[test]
fn qc_shared_string_slices_like_std() {
    quickcheck::quickcheck(
        test_shared_string_slices_like_std as fn(String, SharedStringFromVecFn, Vec<Bounds>),
    )
}

#[test]
fn shared_string_slices_like_std_max_upper_bound() {
    test_shared_string_slices_like_std(
        "0".to_owned(),
        SharedStringFromVecFn(SharedStr::from_string),
        vec![0..1, 0..usize::MAX],
    )
}

fn test_shared_string_slices_like_std(
    string: String,
    new: SharedStringFromVecFn,
    bounds: Vec<Bounds>,
) {
    let mut shared_string = new.call(string.clone());
    let mut std_slice = string.as_str();
    for bound in bounds {
        let actual_result = shared_string.try_slice_into(bound.clone());
        let expected_result = std_slice.get(bound).ok_or(std_slice);
        match actual_result {
            Err(actual) => {
                let expected = expected_result.unwrap_err();
                assert_eq!(actual, expected);
                return;
            }
            Ok(actual) => {
                let expected = expected_result.unwrap();
                assert_eq!(actual, expected);
                shared_string = actual;
                std_slice = expected;
            }
        }
    }
}

#[test]
fn qc_try_split_off() {
    quickcheck::quickcheck(test_try_split_off as fn(SharedStringFromVecFn, String, Bounds, usize))
}

#[test]
fn try_split_off_max_index() {
    test_try_split_off(
        SharedStringFromVecFn(SharedStr::from_string),
        "a".to_owned(),
        0..1,
        usize::MAX,
    )
}

fn test_try_split_off(new: SharedStringFromVecFn, string: String, bounds: Bounds, index: usize) {
    let mut expected_str = match string.get(bounds.clone()) {
        Some(b) => b.to_owned(),
        None => string.clone(),
    };
    let mut actual_str = new
        .call(string)
        .try_slice_into(bounds)
        .unwrap_or_else(identity);
    match actual_str.try_split_off(index) {
        None => assert_eq!(expected_str.get(index..), None),
        Some(actual_split) => {
            let expected_split = expected_str.split_off(index);
            assert_eq!(actual_split, expected_split);
            assert_eq!(actual_str, expected_str);
        }
    };
}

const SHARED_STRING_FROM_STATIC_FNS: &[fn(&'static str) -> SharedStr] = &[
    SharedStr::from_static,
    |b| SharedStr::from_string(b.to_owned()),
    |b| SharedStr::from(Arc::new(b.to_owned())),
];

const SHARED_STRING_FROM_STRING_FNS: &[fn(String) -> SharedStr] = &[
    shared_string_static_from_leak,
    SharedStr::from_string,
    shared_string_arc_string_from_string,
];

fn shared_string_static_from_leak(b: String) -> SharedStr {
    SharedStr::from_static(Box::leak(b.into_boxed_str()))
}

fn shared_string_arc_string_from_string(b: String) -> SharedStr {
    SharedStr::from_arc_string(Arc::new(b))
}

#[derive(Debug, Clone, Copy)]
struct SharedStringFromVecFn(fn(String) -> SharedStr);

impl SharedStringFromVecFn {
    fn call(self, b: String) -> SharedStr {
        (self.0)(b)
    }
}

impl Arbitrary for SharedStringFromVecFn {
    fn arbitrary(g: &mut quickcheck::Gen) -> Self {
        Self(*g.choose(SHARED_STRING_FROM_STRING_FNS).unwrap())
    }
}