Skip to main content

yazi_shared/strand/
buf.rs

1use std::{borrow::Cow, ffi::OsString, hash::{Hash, Hasher}};
2
3use anyhow::Result;
4
5use crate::{path::PathDyn, strand::{AsStrand, Strand, StrandCow, StrandError, StrandKind}, wtf8::FromWtf8Vec};
6
7// --- StrandBuf
8#[derive(Clone, Debug, Eq)]
9pub enum StrandBuf {
10	Os(OsString),
11	Utf8(String),
12	Bytes(Vec<u8>),
13}
14
15impl Default for StrandBuf {
16	fn default() -> Self { Self::Utf8(String::new()) }
17}
18
19impl From<OsString> for StrandBuf {
20	fn from(value: OsString) -> Self { Self::Os(value) }
21}
22
23impl From<&str> for StrandBuf {
24	fn from(value: &str) -> Self { Self::Utf8(value.to_owned()) }
25}
26
27impl From<String> for StrandBuf {
28	fn from(value: String) -> Self { Self::Utf8(value) }
29}
30
31impl From<PathDyn<'_>> for StrandBuf {
32	fn from(value: PathDyn) -> Self {
33		match value {
34			PathDyn::Os(p) => Self::Os(p.as_os_str().to_owned()),
35			PathDyn::Unix(p) => Self::Bytes(p.as_bytes().to_owned()),
36		}
37	}
38}
39
40impl From<StrandCow<'_>> for StrandBuf {
41	fn from(value: StrandCow<'_>) -> Self { value.into_owned() }
42}
43
44impl PartialEq for StrandBuf {
45	fn eq(&self, other: &Self) -> bool { self.as_strand() == other.as_strand() }
46}
47
48impl PartialEq<Strand<'_>> for StrandBuf {
49	fn eq(&self, other: &Strand<'_>) -> bool { self.as_strand() == *other }
50}
51
52impl Hash for StrandBuf {
53	fn hash<H: Hasher>(&self, state: &mut H) { self.as_strand().hash(state); }
54}
55
56impl StrandBuf {
57	pub fn clear(&mut self) {
58		match self {
59			Self::Os(buf) => buf.clear(),
60			Self::Utf8(buf) => buf.clear(),
61			Self::Bytes(buf) => buf.clear(),
62		}
63	}
64
65	#[inline]
66	pub unsafe fn from_encoded_bytes(kind: impl Into<StrandKind>, bytes: Vec<u8>) -> Self {
67		match kind.into() {
68			StrandKind::Utf8 => Self::Utf8(unsafe { String::from_utf8_unchecked(bytes) }),
69			StrandKind::Os => Self::Os(unsafe { OsString::from_encoded_bytes_unchecked(bytes) }),
70			StrandKind::Bytes => Self::Bytes(bytes),
71		}
72	}
73
74	pub fn into_encoded_bytes(self) -> Vec<u8> {
75		match self {
76			Self::Os(s) => s.into_encoded_bytes(),
77			Self::Utf8(s) => s.into_bytes(),
78			Self::Bytes(b) => b,
79		}
80	}
81
82	pub fn into_string_lossy(self) -> String {
83		match self {
84			Self::Os(s) => match s.to_string_lossy() {
85				Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(s.into_encoded_bytes()) },
86				Cow::Owned(s) => s,
87			},
88			Self::Utf8(s) => s,
89			Self::Bytes(b) => match String::from_utf8_lossy(&b) {
90				Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(b) },
91				Cow::Owned(s) => s,
92			},
93		}
94	}
95
96	pub fn new(kind: impl Into<StrandKind>) -> Self { Self::with_str(kind, "") }
97
98	pub fn push_str(&mut self, s: impl AsRef<str>) {
99		let s = s.as_ref();
100		match self {
101			Self::Os(buf) => buf.push(s),
102			Self::Utf8(buf) => buf.push_str(s),
103			Self::Bytes(buf) => buf.extend(s.as_bytes()),
104		}
105	}
106
107	pub fn reserve_exact(&mut self, additional: usize) {
108		match self {
109			Self::Os(buf) => buf.reserve_exact(additional),
110			Self::Utf8(buf) => buf.reserve_exact(additional),
111			Self::Bytes(buf) => buf.reserve_exact(additional),
112		}
113	}
114
115	pub fn try_push<T>(&mut self, s: T) -> Result<(), StrandError>
116	where
117		T: AsStrand,
118	{
119		let s = s.as_strand();
120		Ok(match self {
121			Self::Os(buf) => buf.push(s.as_os()?),
122			Self::Utf8(buf) => buf.push_str(s.as_utf8()?),
123			Self::Bytes(buf) => buf.extend(s.encoded_bytes()),
124		})
125	}
126
127	pub fn with<K>(kind: K, bytes: Vec<u8>) -> Result<Self>
128	where
129		K: Into<StrandKind>,
130	{
131		Ok(match kind.into() {
132			StrandKind::Utf8 => Self::Utf8(String::from_utf8(bytes)?),
133			StrandKind::Os => Self::Os(OsString::from_wtf8_vec(bytes)?),
134			StrandKind::Bytes => Self::Bytes(bytes),
135		})
136	}
137
138	pub fn with_capacity<K>(kind: K, capacity: usize) -> Self
139	where
140		K: Into<StrandKind>,
141	{
142		match kind.into() {
143			StrandKind::Utf8 => Self::Utf8(String::with_capacity(capacity)),
144			StrandKind::Os => Self::Os(OsString::with_capacity(capacity)),
145			StrandKind::Bytes => Self::Bytes(Vec::with_capacity(capacity)),
146		}
147	}
148
149	pub fn with_str<K, S>(kind: K, s: S) -> Self
150	where
151		K: Into<StrandKind>,
152		S: Into<String>,
153	{
154		let s = s.into();
155		match kind.into() {
156			StrandKind::Utf8 => Self::Utf8(s),
157			StrandKind::Os => Self::Os(s.into()),
158			StrandKind::Bytes => Self::Bytes(s.into_bytes()),
159		}
160	}
161}