use std::hash::{Hash, Hasher};
use crate::parser::{RawString, StringEncoding};
#[derive(Debug, Clone, Default)]
pub struct LuaString {
bytes: Vec<u8>,
text: Option<String>,
encoding: Option<StringEncoding>,
}
impl PartialEq for LuaString {
fn eq(&self, other: &Self) -> bool {
self.bytes == other.bytes
}
}
impl Eq for LuaString {}
impl PartialOrd for LuaString {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for LuaString {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.bytes.cmp(&other.bytes)
}
}
impl Hash for LuaString {
fn hash<H: Hasher>(&self, state: &mut H) {
self.bytes.hash(state);
}
}
impl LuaString {
pub fn from_raw(raw: &RawString) -> Self {
Self {
bytes: raw.bytes.clone(),
text: raw.text.as_ref().map(|text| text.value.clone()),
encoding: raw.text.as_ref().map(|text| text.encoding),
}
}
pub fn from_bytes(bytes: Vec<u8>) -> Self {
Self {
bytes,
text: None,
encoding: None,
}
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn decoded_text(&self) -> Option<&str> {
self.text.as_deref()
}
pub fn preferred_text(&self) -> Option<&str> {
match self.encoding {
Some(StringEncoding::EncodingRs(enc))
if std::ptr::eq(enc, encoding_rs::WINDOWS_1252) =>
{
None
}
_ => self.decoded_text(),
}
}
pub fn as_utf8(&self) -> Option<&str> {
std::str::from_utf8(&self.bytes).ok()
}
pub fn debug_literal(&self) -> String {
self.preferred_text()
.or_else(|| self.as_utf8())
.map_or_else(
|| {
let bytes = self
.bytes
.iter()
.map(|byte| format!("{byte:02x}"))
.collect::<Vec<_>>()
.join(" ");
format!("<{} bytes: {bytes}>", self.bytes.len())
},
|text| format!("{text:?}"),
)
}
}
impl From<&str> for LuaString {
fn from(value: &str) -> Self {
Self {
bytes: value.as_bytes().to_vec(),
text: Some(value.to_owned()),
encoding: Some(StringEncoding::Utf8),
}
}
}
impl From<String> for LuaString {
fn from(value: String) -> Self {
Self {
bytes: value.as_bytes().to_vec(),
text: Some(value),
encoding: Some(StringEncoding::Utf8),
}
}
}