Skip to main content

yazi_shared/
snake_cased_string.rs

1use std::{borrow::Borrow, ffi::OsStr, fmt::{Display, Formatter}, ops::Deref};
2
3use serde::{Deserialize, Deserializer, Serialize};
4
5use crate::BytesExt;
6
7#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
8#[serde(transparent)]
9pub struct SnakeCasedString(pub(super) String);
10
11impl SnakeCasedString {
12	pub fn new(s: String) -> Option<Self> { s.as_bytes().snake_cased().then_some(Self(s)) }
13}
14
15impl Deref for SnakeCasedString {
16	type Target = str;
17
18	#[inline]
19	fn deref(&self) -> &Self::Target { &self.0 }
20}
21
22impl Borrow<str> for SnakeCasedString {
23	#[inline]
24	fn borrow(&self) -> &str { &self.0 }
25}
26
27impl Borrow<String> for SnakeCasedString {
28	#[inline]
29	fn borrow(&self) -> &String { &self.0 }
30}
31
32impl AsRef<str> for SnakeCasedString {
33	#[inline]
34	fn as_ref(&self) -> &str { &self.0 }
35}
36
37impl AsRef<OsStr> for SnakeCasedString {
38	#[inline]
39	fn as_ref(&self) -> &OsStr { self.0.as_ref() }
40}
41
42impl Display for SnakeCasedString {
43	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { Display::fmt(&self.0, f) }
44}
45
46impl From<SnakeCasedString> for String {
47	#[inline]
48	fn from(value: SnakeCasedString) -> Self { value.0 }
49}
50
51impl<'de> Deserialize<'de> for SnakeCasedString {
52	fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
53		let value = String::deserialize(deserializer)?;
54		Self::new(value).ok_or_else(|| serde::de::Error::custom("must be a snake-cased string"))
55	}
56}