use std::sync::{Arc, RwLock, RwLockReadGuard};
use crate::util::{Utf16String, ValidateError};
pub struct FragmentSignature {
fragment_name: Utf16String,
parameter_names: Option<Arc<RwLock<Vec<Option<Utf16String>>>>>,
}
impl FragmentSignature {
pub fn new(
fragment_name: Option<Utf16String>,
parameter_names: Option<Arc<RwLock<Vec<Option<Utf16String>>>>>,
) -> Result<Self, ValidateError> {
let fragment_name = fragment_name
.filter(|value| !value.is_empty())
.ok_or_else(|| ValidateError::IllegalArgument {
message: Some("Fragment name cannot be null or empty".to_owned()),
})?;
Ok(Self {
fragment_name,
parameter_names,
})
}
pub fn get_fragment_name(&self) -> &Utf16String {
&self.fragment_name
}
pub fn has_parameters(&self) -> bool {
self.parameter_names
.as_ref()
.is_some_and(|parameters| !read_recovering_poison(parameters).is_empty())
}
pub fn get_parameter_names(&self) -> Option<RwLockReadGuard<'_, Vec<Option<Utf16String>>>> {
self.parameter_names
.as_ref()
.map(|parameters| read_recovering_poison(parameters))
}
pub fn get_string_representation(&self) -> Utf16String {
let Some(parameter_names) = self.parameter_names.as_ref() else {
return self.fragment_name.clone();
};
let parameters = read_recovering_poison(parameter_names);
if parameters.is_empty() {
return self.fragment_name.clone();
}
let mut units = self.fragment_name.as_utf16().to_vec();
units.extend_from_slice(&[b' ' as u16, b'(' as u16]);
for (index, parameter) in parameters.iter().enumerate() {
if index != 0 {
units.push(b',' as u16);
}
match parameter {
Some(parameter) => units.extend_from_slice(parameter.as_utf16()),
None => units.extend("null".encode_utf16()),
}
}
units.push(b')' as u16);
Utf16String::from_utf16(units)
}
}
fn read_recovering_poison<T>(lock: &RwLock<T>) -> RwLockReadGuard<'_, T> {
lock.read()
.unwrap_or_else(std::sync::PoisonError::into_inner)
}