use std::io;
use std::sync::RwLock;
use super::{
CharSequenceValue, HashCodeValue, IWritableCharSequence, TemplateWriter, TextUtilsError,
Utf16String,
};
pub trait LazyCharSequenceResolver: Send + Sync {
fn class_name(&self) -> &str;
fn resolve_text(&self) -> Option<Utf16String>;
fn write_unresolved(&self, writer: &mut dyn TemplateWriter) -> io::Result<()>;
}
pub struct AbstractLazyCharSequence<R: LazyCharSequenceResolver> {
resolver: R,
resolved_text: RwLock<Option<Utf16String>>,
}
impl<R: LazyCharSequenceResolver> AbstractLazyCharSequence<R> {
#[must_use]
pub const fn new(resolver: R) -> Self {
Self {
resolver,
resolved_text: RwLock::new(None),
}
}
pub fn get_text(&self) -> Option<Utf16String> {
if let Some(value) = read_lock(&self.resolved_text).as_ref() {
return Some(value.clone());
}
let value = self.resolver.resolve_text();
*write_lock(&self.resolved_text) = value.clone();
value
}
pub fn equals_java(&self, other: &Self) -> Result<bool, TextUtilsError> {
if std::ptr::eq(self, other) {
return Ok(true);
}
if self.resolver.class_name() != other.resolver.class_name() {
return Ok(false);
}
let left = self.get_text().ok_or(TextUtilsError::NullPointer)?;
let right = other.get_text().ok_or(TextUtilsError::NullPointer)?;
Ok(left == right)
}
pub fn hash_code(&self) -> Result<i32, TextUtilsError> {
self.get_text()
.ok_or(TextUtilsError::NullPointer)
.map(|value| value.hash_code())
}
pub fn to_utf16_string(&self) -> Result<Utf16String, TextUtilsError> {
self.get_text().ok_or(TextUtilsError::NullPointer)
}
}
impl<R: LazyCharSequenceResolver> CharSequenceValue for AbstractLazyCharSequence<R> {
fn length(&self) -> Result<i32, TextUtilsError> {
Ok(self.get_text().ok_or(TextUtilsError::NullPointer)?.len() as i32)
}
fn char_at(&self, index: i32) -> Result<u16, TextUtilsError> {
self.get_text()
.ok_or(TextUtilsError::NullPointer)?
.char_at(index)
}
fn as_utf16_string(&self) -> Option<&Utf16String> {
None
}
fn to_utf16_string(&self) -> Result<Utf16String, TextUtilsError> {
self.to_utf16_string()
}
fn sub_sequence(&self, start: i32, end: i32) -> Result<Utf16String, TextUtilsError> {
self.get_text()
.ok_or(TextUtilsError::NullPointer)?
.sub_sequence(start, end)
}
fn write_direct(&self, writer: &mut dyn TemplateWriter) -> Option<io::Result<()>> {
Some(IWritableCharSequence::write(self, writer))
}
}
impl<R: LazyCharSequenceResolver> IWritableCharSequence for AbstractLazyCharSequence<R> {
fn write(&self, writer: &mut dyn TemplateWriter) -> io::Result<()> {
if let Some(value) = read_lock(&self.resolved_text).as_ref() {
writer.write_utf16(value.as_utf16())
} else {
self.resolver.write_unresolved(writer)
}
}
}
fn read_lock<T>(lock: &RwLock<T>) -> std::sync::RwLockReadGuard<'_, T> {
lock.read()
.unwrap_or_else(std::sync::PoisonError::into_inner)
}
fn write_lock<T>(lock: &RwLock<T>) -> std::sync::RwLockWriteGuard<'_, T> {
lock.write()
.unwrap_or_else(std::sync::PoisonError::into_inner)
}