use crate::ule::*;
use core::cmp::{Ord, Ordering, PartialOrd};
use core::fmt;
use core::ops::Deref;
use super::*;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
pub struct VarZeroVec<'a, T: ?Sized, F = Index16>(pub(crate) VarZeroVecInner<'a, T, F>);
pub(crate) enum VarZeroVecInner<'a, T: ?Sized, F = Index16> {
#[cfg(feature = "alloc")]
Owned(VarZeroVecOwned<T, F>),
Borrowed(&'a VarZeroSlice<T, F>),
}
impl<'a, T: ?Sized, F> Clone for VarZeroVec<'a, T, F> {
fn clone(&self) -> Self {
match self.0 {
#[cfg(feature = "alloc")]
VarZeroVecInner::Owned(ref o) => o.clone().into(),
VarZeroVecInner::Borrowed(b) => b.into(),
}
}
}
impl<T: VarULE + ?Sized, F: VarZeroVecFormat> fmt::Debug for VarZeroVec<'_, T, F>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
VarZeroSlice::fmt(self, f)
}
}
#[cfg(feature = "alloc")]
impl<'a, T: ?Sized, F> From<VarZeroVecOwned<T, F>> for VarZeroVec<'a, T, F> {
#[inline]
fn from(other: VarZeroVecOwned<T, F>) -> Self {
Self(VarZeroVecInner::Owned(other))
}
}
impl<'a, T: ?Sized, F> From<&'a VarZeroSlice<T, F>> for VarZeroVec<'a, T, F> {
fn from(other: &'a VarZeroSlice<T, F>) -> Self {
Self(VarZeroVecInner::Borrowed(other))
}
}
#[cfg(feature = "alloc")]
impl<'a, T: ?Sized + VarULE, F: VarZeroVecFormat> From<VarZeroVec<'a, T, F>>
for VarZeroVecOwned<T, F>
{
#[inline]
fn from(other: VarZeroVec<'a, T, F>) -> Self {
match other.0 {
VarZeroVecInner::Owned(o) => o,
VarZeroVecInner::Borrowed(b) => b.into(),
}
}
}
impl<T: VarULE + ?Sized, F: VarZeroVecFormat> Default for VarZeroVec<'_, T, F> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T: VarULE + ?Sized, F: VarZeroVecFormat> Deref for VarZeroVec<'_, T, F> {
type Target = VarZeroSlice<T, F>;
fn deref(&self) -> &VarZeroSlice<T, F> {
self.as_slice()
}
}
impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVec<'a, T, F> {
#[inline]
pub const fn new() -> Self {
Self(VarZeroVecInner::Borrowed(VarZeroSlice::new_empty()))
}
pub fn parse_bytes(slice: &'a [u8]) -> Result<Self, UleError> {
let borrowed = VarZeroSlice::<T, F>::parse_bytes(slice)?;
Ok(Self(VarZeroVecInner::Borrowed(borrowed)))
}
pub const unsafe fn from_bytes_unchecked(bytes: &'a [u8]) -> Self {
Self(VarZeroVecInner::Borrowed(core::mem::transmute::<
&[u8],
&VarZeroSlice<T, F>,
>(bytes)))
}
#[cfg(feature = "alloc")]
pub fn make_mut(&mut self) -> &mut VarZeroVecOwned<T, F> {
match self.0 {
VarZeroVecInner::Owned(ref mut vec) => vec,
VarZeroVecInner::Borrowed(slice) => {
let new_self = VarZeroVecOwned::from_slice(slice);
*self = new_self.into();
self.make_mut()
}
}
}
#[cfg(feature = "alloc")]
pub fn into_owned(mut self) -> VarZeroVec<'static, T, F> {
self.make_mut();
match self.0 {
VarZeroVecInner::Owned(vec) => vec.into(),
_ => unreachable!(),
}
}
pub fn as_slice(&self) -> &VarZeroSlice<T, F> {
match self.0 {
#[cfg(feature = "alloc")]
VarZeroVecInner::Owned(ref owned) => owned,
VarZeroVecInner::Borrowed(b) => b,
}
}
#[cfg(feature = "alloc")]
pub fn into_bytes(self) -> Vec<u8> {
match self.0 {
VarZeroVecInner::Owned(vec) => vec.into_bytes(),
VarZeroVecInner::Borrowed(vec) => vec.as_bytes().to_vec(),
}
}
pub fn is_owned(&self) -> bool {
match self.0 {
#[cfg(feature = "alloc")]
VarZeroVecInner::Owned(..) => true,
VarZeroVecInner::Borrowed(..) => false,
}
}
#[doc(hidden)]
pub fn as_components<'b>(&'b self) -> VarZeroVecComponents<'b, T, F> {
self.as_slice().as_components()
}
}
#[cfg(feature = "alloc")]
impl<A, T, F> From<&Vec<A>> for VarZeroVec<'static, T, F>
where
T: VarULE + ?Sized,
A: EncodeAsVarULE<T>,
F: VarZeroVecFormat,
{
#[inline]
fn from(elements: &Vec<A>) -> Self {
Self::from(elements.as_slice())
}
}
#[cfg(feature = "alloc")]
impl<A, T, F> From<&[A]> for VarZeroVec<'static, T, F>
where
T: VarULE + ?Sized,
A: EncodeAsVarULE<T>,
F: VarZeroVecFormat,
{
#[inline]
fn from(elements: &[A]) -> Self {
if elements.is_empty() {
VarZeroSlice::new_empty().into()
} else {
#[expect(clippy::unwrap_used)] VarZeroVecOwned::try_from_elements(elements).unwrap().into()
}
}
}
#[cfg(feature = "alloc")]
impl<A, T, F, const N: usize> From<&[A; N]> for VarZeroVec<'static, T, F>
where
T: VarULE + ?Sized,
A: EncodeAsVarULE<T>,
F: VarZeroVecFormat,
{
#[inline]
fn from(elements: &[A; N]) -> Self {
Self::from(elements.as_slice())
}
}
impl<'a, 'b, T, F> PartialEq<VarZeroVec<'b, T, F>> for VarZeroVec<'a, T, F>
where
T: VarULE,
T: ?Sized,
T: PartialEq,
F: VarZeroVecFormat,
{
#[inline]
fn eq(&self, other: &VarZeroVec<'b, T, F>) -> bool {
if self.is_empty() || other.is_empty() {
return self.is_empty() && other.is_empty();
}
self.as_bytes().eq(other.as_bytes())
}
}
impl<'a, T, F> Eq for VarZeroVec<'a, T, F>
where
T: VarULE,
T: ?Sized,
T: Eq,
F: VarZeroVecFormat,
{
}
impl<T, A, F> PartialEq<&'_ [A]> for VarZeroVec<'_, T, F>
where
T: VarULE + ?Sized,
T: PartialEq,
A: AsRef<T>,
F: VarZeroVecFormat,
{
#[inline]
fn eq(&self, other: &&[A]) -> bool {
self.iter().eq(other.iter().map(|t| t.as_ref()))
}
}
impl<T, A, F, const N: usize> PartialEq<[A; N]> for VarZeroVec<'_, T, F>
where
T: VarULE + ?Sized,
T: PartialEq,
A: AsRef<T>,
F: VarZeroVecFormat,
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
self.iter().eq(other.iter().map(|t| t.as_ref()))
}
}
impl<'a, T: VarULE + ?Sized + PartialOrd, F: VarZeroVecFormat> PartialOrd for VarZeroVec<'a, T, F> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<'a, T: VarULE + ?Sized + Ord, F: VarZeroVecFormat> Ord for VarZeroVec<'a, T, F> {
fn cmp(&self, other: &Self) -> Ordering {
self.iter().cmp(other.iter())
}
}
#[test]
fn assert_single_empty_representation() {
assert_eq!(
VarZeroVec::<str>::new().as_bytes(),
VarZeroVec::<str>::from(&[] as &[&str]).as_bytes()
);
use crate::map::MutableZeroVecLike;
let mut vzv = VarZeroVec::<str>::from(&["hello", "world"][..]);
assert_eq!(vzv.len(), 2);
assert!(!vzv.as_bytes().is_empty());
vzv.zvl_remove(0);
assert_eq!(vzv.len(), 1);
assert!(!vzv.as_bytes().is_empty());
vzv.zvl_remove(0);
assert_eq!(vzv.len(), 0);
assert!(vzv.as_bytes().is_empty());
vzv.zvl_insert(0, "something");
assert_eq!(vzv.len(), 1);
assert!(!vzv.as_bytes().is_empty());
}
#[test]
fn weird_empty_representation_equality() {
assert_eq!(
VarZeroVec::<str>::parse_bytes(&[0, 0, 0, 0]).unwrap(),
VarZeroVec::<str>::parse_bytes(&[]).unwrap()
);
}