use crate::thread::Thread;
use crate::{JavaObject, Result};
use ahash::AHashMap;
use ristretto_classfile::{JavaStr, JavaString};
use ristretto_classloader::Value;
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Debug)]
pub struct StringPool {
strings: Arc<RwLock<AHashMap<JavaString, Value>>>,
}
impl StringPool {
pub fn new() -> Self {
StringPool {
strings: Arc::new(RwLock::new(AHashMap::default())),
}
}
pub async fn intern_java_str(&self, thread: &Thread, string: &JavaStr) -> Result<Value> {
{
let strings = self.strings.read().await;
if let Some(value) = strings.get(string) {
return Ok(value.clone());
}
}
let value = string.to_object(thread).await?;
let mut strings = self.strings.write().await;
let key = string.to_java_string();
let entry = strings.entry(key).or_insert_with(|| value);
Ok(entry.clone())
}
pub async fn intern(&self, thread: &Thread, string: &str) -> Result<Value> {
let java_string = JavaString::from(string);
let java_str: &JavaStr = &java_string;
{
let strings = self.strings.read().await;
if let Some(value) = strings.get(java_str) {
return Ok(value.clone());
}
}
let value = string.to_object(thread).await?;
let mut strings = self.strings.write().await;
let entry = strings.entry(java_string).or_insert_with(|| value);
Ok(entry.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test::thread;
#[tokio::test]
async fn test_string_pool() -> Result<()> {
let (_givm, thread) = thread().await?;
let string_pool = StringPool::new();
let value1 = string_pool.intern(&thread, "Hello").await?;
let value2 = string_pool.intern(&thread, "Hello").await?;
assert_eq!(value1, value2);
Ok(())
}
#[tokio::test]
async fn test_string_pool_java_str() -> Result<()> {
let (_givm, thread) = thread().await?;
let string_pool = StringPool::new();
let js = JavaString::from("Hello");
let value1 = string_pool.intern_java_str(&thread, &js).await?;
let value2 = string_pool.intern_java_str(&thread, &js).await?;
assert_eq!(value1, value2);
Ok(())
}
}