use language_tags::LanguageTag;
use std::collections::HashMap;
#[cfg(feature = "taganak")]
use futures_util::stream::TryStreamExt;
#[cfg(feature = "taganak")]
use taganak_core::prelude::{GraphError, GraphView, Term};
#[derive(Debug, Default, Clone)]
pub struct LangString {
langs: HashMap<LanguageTag, String>,
default: Option<String>,
}
impl LangString {
pub fn set(&mut self, language: LanguageTag, string: String) {
self.langs.insert(language, string);
}
pub fn set_default(&mut self, string: String) {
let _ = self.default.insert(string);
}
pub fn unset(&mut self, language: &LanguageTag) {
self.langs.remove(language);
}
pub fn unset_default(&mut self) {
self.default.take();
}
pub fn get(&self, language: &LanguageTag) -> Option<&str> {
if let Some(string) = self.langs.get(language) {
return Some(string);
}
for known_lang in self.langs.keys() {
if !known_lang.is_language_range() {
continue;
}
if known_lang.matches(language) {
return self.langs.get(known_lang).map(|s| s.as_str());
}
}
self.default.as_ref().map(|s| s.as_str())
}
#[cfg(feature = "taganak")]
pub async fn from_graph<G>(
graph: G,
subject: &Term,
predicate: &Term,
) -> Result<Self, GraphError>
where
G: GraphView + Clone,
{
use std::sync::Arc;
let mut lang_string = Self::default();
static LIMIT: usize = 256;
let mut stream = graph
.objects(Some(subject), Some(predicate), Some(LIMIT))
.await?;
while let Some(object) = stream.try_next().await? {
let object: Arc<Term> = object;
if !object.is_literal() {
continue;
}
let literal = object.to_literal().expect("we just checked");
match literal.datatype() {
"http://www.w3.org/2001/XMLSchema#string" => {
lang_string.set_default(literal.lexical().to_string())
}
"http://www.w3.org/1999/02/22-rdf-syntax-ns#langString"
| "http://www.w3.org/1999/02/22-rdf-syntax-ns#dirLangString" => lang_string.set(
literal.language().expect("we just checked").clone(),
literal.lexical().to_string(),
),
_ => continue,
}
}
Ok(lang_string)
}
}