use crate::{
object::{InvalidExpandedJson, LiteralString},
Direction, LenientLanguageTag, LenientLanguageTagBuf,
};
use locspan::Meta;
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct LangString {
data: LiteralString,
language: Option<LenientLanguageTagBuf>,
direction: Option<Direction>,
}
#[derive(Clone, Copy, Debug)]
pub struct InvalidLangString;
impl LangString {
pub fn new(
data: LiteralString,
language: Option<LenientLanguageTagBuf>,
direction: Option<Direction>,
) -> Result<Self, LiteralString> {
if language.is_some() || direction.is_some() {
Ok(Self {
data,
language,
direction,
})
} else {
Err(data)
}
}
pub fn into_parts(
self,
) -> (
LiteralString,
Option<LenientLanguageTagBuf>,
Option<Direction>,
) {
(self.data, self.language, self.direction)
}
pub fn parts(&self) -> (&str, Option<&LenientLanguageTagBuf>, Option<&Direction>) {
(&self.data, self.language.as_ref(), self.direction.as_ref())
}
#[inline(always)]
pub fn as_str(&self) -> &str {
self.data.as_ref()
}
#[inline(always)]
pub fn language(&self) -> Option<LenientLanguageTag> {
self.language.as_ref().map(|tag| tag.as_ref())
}
pub fn set_language(
&mut self,
language: Option<LenientLanguageTagBuf>,
) -> Result<(), InvalidLangString> {
if self.direction.is_some() || language.is_some() {
self.language = language;
Ok(())
} else {
Err(InvalidLangString)
}
}
#[inline(always)]
pub fn direction(&self) -> Option<Direction> {
self.direction
}
pub fn set_direction(&mut self, direction: Option<Direction>) -> Result<(), InvalidLangString> {
if direction.is_some() || self.language.is_some() {
self.direction = direction;
Ok(())
} else {
Err(InvalidLangString)
}
}
pub fn set(
&mut self,
language: Option<LenientLanguageTagBuf>,
direction: Option<Direction>,
) -> Result<(), InvalidLangString> {
if direction.is_some() || language.is_some() {
self.language = language;
self.direction = direction;
Ok(())
} else {
Err(InvalidLangString)
}
}
pub(crate) fn try_from_json<M>(
object: json_syntax::Object<M>,
value: Meta<json_syntax::Value<M>, M>,
language: Option<Meta<json_syntax::Value<M>, M>>,
direction: Option<Meta<json_syntax::Value<M>, M>>,
) -> Result<Self, Meta<InvalidExpandedJson<M>, M>> {
let data = match value {
Meta(json_syntax::Value::String(s), _) => s.into(),
Meta(v, meta) => {
return Err(Meta(
InvalidExpandedJson::Unexpected(v.kind(), json_syntax::Kind::String),
meta,
))
}
};
let language = match language {
Some(Meta(json_syntax::Value::String(value), _)) => {
let (tag, _) = LenientLanguageTagBuf::new(value.to_string());
Some(tag)
}
Some(Meta(v, meta)) => {
return Err(Meta(
InvalidExpandedJson::Unexpected(v.kind(), json_syntax::Kind::String),
meta,
))
}
None => None,
};
let direction = match direction {
Some(Meta(json_syntax::Value::String(value), meta)) => {
match Direction::try_from(value.as_str()) {
Ok(direction) => Some(direction),
Err(_) => return Err(Meta(InvalidExpandedJson::InvalidDirection, meta)),
}
}
Some(Meta(v, meta)) => {
return Err(Meta(
InvalidExpandedJson::Unexpected(v.kind(), json_syntax::Kind::String),
meta,
))
}
None => None,
};
match object.into_iter().next() {
None => Ok(Self::new(data, language, direction).unwrap()),
Some(entry) => Err(Meta(
InvalidExpandedJson::UnexpectedEntry,
entry.key.into_metadata(),
)),
}
}
}