1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use {
	crate::{lua::LuaError, prelude::*},
	glib::variant::VariantTypeMismatchError,
	std::{fmt, ops::Deref, str},
};

newtype_wrapper! {
	#[derive(Debug, Ord, Eq, Clone, Hash)]
	pub struct LuaString([u8] | Vec<u8> = Self) as_bytes into_bytes;
}

impl<'a> LuaString<'a> {
	pub fn as_str(&self) -> Result<&str, str::Utf8Error> {
		str::from_utf8(self.as_bytes())
	}

	pub fn into_string(self) -> Result<String, str::Utf8Error> {
		match self.as_str() {
			Ok(..) => Ok(unsafe { String::from_utf8_unchecked(self.into_bytes()) }),
			Err(e) => Err(e),
		}
	}

	pub fn to_variant(&self) -> Variant {
		match self.as_str() {
			Ok(s) => s.to_variant(),
			Err(..) => self.as_bytes().to_variant(),
		}
	}

	pub fn parse<F: FromStr>(&self) -> Result<F, LuaError>
	where
		F::Err: Into<LuaError>,
	{
		self
			.as_str()
			.map_err(Into::into)
			.and_then(|s| s.parse().map_err(Into::into))
	}
}

impl<'a> Deref for LuaString<'a> {
	type Target = [u8];

	fn deref(&self) -> &Self::Target {
		self.as_bytes()
	}
}

impl<'a> TryFrom<&'a Variant> for LuaString<'a> {
	type Error = LuaError;

	fn try_from(variant: &'a Variant) -> Result<Self, Self::Error> {
		match variant.classify() {
			VariantClass::Variant => Self::try_from(variant.as_variant().expect("VariantClass")),
			VariantClass::String => Ok(Self::from(variant.str().expect("VariantClass"))),
			VariantClass::Array if variant.type_() == VariantTy::BYTE_STRING =>
				Ok(Self::from(variant.fixed_array::<u8>().expect("VariantClass"))),
			_ => Err(LuaError::TypeMismatch(VariantTypeMismatchError::new(
				variant.type_().to_owned(),
				VariantTy::STRING.to_owned(),
			))),
		}
	}
}

impl<'a> TryFrom<Variant> for LuaString<'a> {
	type Error = LuaError;

	fn try_from(variant: Variant) -> Result<Self, Self::Error> {
		LuaString::try_from(&variant).map(|s| s.owned())
	}
}

impl<'a> Into<Variant> for LuaString<'a> {
	fn into(self) -> Variant {
		Into::into(&self)
	}
}

impl<'a> From<String> for LuaString<'a> {
	fn from(v: String) -> Self {
		Self::from(v.into_bytes())
	}
}

impl<'a> From<&'a str> for LuaString<'a> {
	fn from(v: &'a str) -> Self {
		Self::from(v.as_bytes())
	}
}

impl fmt::Display for LuaString<'_> {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		match self.as_str() {
			Ok(s) => fmt::Display::fmt(s, f),
			Err(_) => todo!(),
		}
	}
}