use std::slice::SliceIndex;
pub trait Digest {
fn validate(&self, n: usize) -> bool;
fn as_bytes(&self) -> &[u8];
fn get<I: SliceIndex<Self>>(&self, i: I) -> Option<&I::Output>;
unsafe fn get_unchecked<I: SliceIndex<Self>>(&self, i: I) -> &I::Output;
}
impl Digest for [u8] {
#[inline]
fn validate(&self, n: usize) -> bool {
n <= self.len()
}
#[inline]
fn as_bytes(&self) -> &[u8] {
self
}
#[inline]
fn get<I: SliceIndex<Self>>(&self, i: I) -> Option<&I::Output> {
self.get(i)
}
#[inline]
unsafe fn get_unchecked<I: SliceIndex<Self>>(&self, i: I) -> &I::Output {
self.get_unchecked(i)
}
}
impl Digest for str {
#[inline]
fn validate(&self, n: usize) -> bool {
self.is_char_boundary(n)
}
#[inline]
fn as_bytes(&self) -> &[u8] {
self.as_bytes()
}
#[inline]
fn get<I: SliceIndex<Self>>(&self, i: I) -> Option<&I::Output> {
self.get(i)
}
#[inline]
unsafe fn get_unchecked<I: SliceIndex<Self>>(&self, i: I) -> &I::Output {
self.get_unchecked(i)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn digest_bytes() {
let bytes = b"123" as &[u8];
assert!(bytes.validate(0));
assert!(bytes.validate(1));
assert!(bytes.validate(2));
assert!(bytes.validate(3));
assert!(!bytes.validate(4));
assert_eq!(bytes.as_bytes(), b"123");
assert_eq!(<[u8] as Digest>::get(bytes, 0), Some(&b'1'));
assert_eq!(<[u8] as Digest>::get(bytes, 0..), Some(b"123" as &[u8]));
assert_eq!(unsafe { <[u8] as Digest>::get_unchecked(bytes, 0) }, &b'1');
assert_eq!(
unsafe { <[u8] as Digest>::get_unchecked(bytes, 0..) },
b"123"
);
}
#[test]
fn digest_str() {
let text = "好";
assert!(text.validate(0));
assert!(!text.validate(1));
assert!(!text.validate(2));
assert!(text.validate(3));
assert!(!text.validate(4));
assert_eq!(<str as Digest>::as_bytes(text), [229, 165, 189]);
assert_eq!(<str as Digest>::get(text, 0..), Some("好"));
assert_eq!(unsafe { <str as Digest>::get_unchecked(text, 0..) }, "好");
}
}