yazi_shared/strand/
buf.rs1use 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#[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}