daemonic_error 0.2.0

Errors that compose, predict, and leave receipts - Compose: algebraic combination (in active development) - Predict: Glass/Severity - Receipts: audit trail, position, checksum - Reflection: Runtime Reflection through TopologySegment (in active development)
use alloc::borrow::Cow;
use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::string::String;
use alloc::sync::Arc;
use core::fmt::{Formatter, Octal};
use core::{fmt, mem};
// use crate::daemonic_path_buffer::daemonic_os_str::DaemonicSlice;
use super::*;
pub struct DaemonicSlice {
	pub inner: [u8],
}
impl fmt::Debug for DaemonicSlice {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		fmt::Debug::fmt(&self.inner.utf8_chunks().debug(), f)
	}
}
unsafe impl core::clone::CloneToUninit for DaemonicSlice {
	unsafe fn clone_to_uninit(&self, dst: *mut u8) {
		// DaemonicSlice wraps [u8] transparently.
		// Copy the bytes directly.
		let bytes = self.as_encoded_bytes();
		core::ptr::copy_nonoverlapping(
			bytes.as_ptr(),
			dst,
			bytes.len(),
		);
	}
}
use core::fmt::Write;
impl fmt::Display for DaemonicSlice {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		// If we're the empty string then our iterator won't actually yield
		// anything, so perform the formatting manually
		if self.inner.is_empty() {
			return "".fmt(f);
		}
		
		for chunk in self.inner.utf8_chunks() {
			let valid = chunk.valid();
			// If we successfully decoded the whole chunk as a valid string then
			// we can return a direct formatting of the string which will also
			// respect various formatting flags if possible.
			if chunk.invalid().is_empty() {
				return valid.fmt(f);
			}
			
			f.write_str(valid)?;
			Formatter::write_char(f, char::REPLACEMENT_CHARACTER)?;
		}
		Ok(())
	}
}
impl DaemonicSlice {
	#[inline]
	pub fn as_encoded_bytes(&self) -> &[u8] {
		&self.inner
	}
	
	#[inline]
	pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &DaemonicSlice {
		unsafe { mem::transmute(s) }
	}
	
	#[track_caller]
	#[inline]
	pub fn check_public_boundary(&self, index: usize) {
		if index == 0 || index == self.inner.len() {
			return;
		}
		if index < self.inner.len()
			&& (self.inner[index - 1].is_ascii() || self.inner[index].is_ascii())
		{
			return;
		}
		
		slow_path(&self.inner, index);
		
		/// We're betting that typical splits will involve an ASCII character.
		///
		/// Putting the expensive checks in a separate function generates notably
		/// better assembly.
		#[track_caller]
		#[inline(never)]
		fn slow_path(bytes: &[u8], index: usize) {
			let (before, after) = bytes.split_at(index);
			
			// UTF-8 takes at most 4 bytes per codepoint, so we don't
			// need to check more than that.
			let after = after.get(..4).unwrap_or(after);
			match str::from_utf8(after) {
				Ok(_) => return,
				Err(err) if err.valid_up_to() != 0 => return,
				Err(_) => (),
			}
			
			for len in 2..=4.min(index) {
				let before = &before[index - len..];
				if str::from_utf8(before).is_ok() {
					return;
				}
			}
			
			panic!("byte index {index} is not an DaemonicOsStr boundary");
		}
	}
	
	#[inline]
	pub fn from_str(s: &str) -> &DaemonicSlice {
		unsafe { DaemonicSlice::from_encoded_bytes_unchecked(s.as_bytes()) }
	}
	
	#[inline]
	pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
		str::from_utf8(&self.inner)
	}
	
	#[inline]
	pub fn to_string_lossy(&self) -> Cow<'_, str> {
		String::from_utf8_lossy(&self.inner)
	}
	
	#[inline]
	pub fn to_owned(&self) -> DaemonicBuf {
		DaemonicBuf { inner: self.inner.to_vec() }
	}
	
	#[inline]
	pub fn clone_into(&self, buf: &mut DaemonicBuf) {
		self.inner.clone_into(&mut buf.inner)
	}
	
	#[inline]
	pub fn into_box(&self) -> Box<DaemonicSlice> {
		let boxed: Box<[u8]> = self.inner.into();
		unsafe { mem::transmute(boxed) }
	}
	
	#[inline]
	pub fn empty_box() -> Box<DaemonicSlice> {
		let boxed: Box<[u8]> = Default::default();
		unsafe { mem::transmute(boxed) }
	}
	
	#[inline]
	pub fn into_arc(&self) -> Arc<DaemonicSlice> {
		let arc: Arc<[u8]> = Arc::from(&self.inner);
		unsafe { Arc::from_raw(Arc::into_raw(arc) as *const DaemonicSlice) }
	}
	
	#[inline]
	pub fn into_rc(&self) -> Rc<DaemonicSlice> {
		let rc: Rc<[u8]> = Rc::from(&self.inner);
		unsafe { Rc::from_raw(Rc::into_raw(rc) as *const DaemonicSlice) }
	}
	
	#[inline]
	pub fn make_ascii_lowercase(&mut self) {
		self.inner.make_ascii_lowercase()
	}
	
	#[inline]
	pub fn make_ascii_uppercase(&mut self) {
		self.inner.make_ascii_uppercase()
	}
	
	#[inline]
	pub fn to_ascii_lowercase(&self) -> DaemonicBuf {
		DaemonicBuf { inner: self.inner.to_ascii_lowercase() }
	}
	
	#[inline]
	pub fn to_ascii_uppercase(&self) -> DaemonicBuf {
		DaemonicBuf { inner: self.inner.to_ascii_uppercase() }
	}
	
	#[inline]
	pub fn is_ascii(&self) -> bool {
		self.inner.is_ascii()
	}
	
	#[inline]
	pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
		self.inner.eq_ignore_ascii_case(&other.inner)
	}
}