use crate::Pollable;
use std::{
cell::RefCell,
pin::Pin,
sync::{Arc, RwLock},
};
pub mod msg_id {
const BASE: u16 = 94;
const OFFSET: u8 = b'!';
const MAX_ID: u16 = BASE * BASE - 1;
pub fn to_u16(id_str: &str) -> Result<u16, &'static str> {
if id_str.len() != 2 {
return Err("Input string must be exactly 2 characters long.");
}
let bytes = id_str.as_bytes();
let c1 = bytes[0];
let c2 = bytes[1];
if !(c1 >= b'!' && c1 <= b'~' && c2 >= b'!' && c2 <= b'~') {
return Err("Input string contains invalid characters.");
}
let val1 = (c1 - OFFSET) as u16;
let val2 = (c2 - OFFSET) as u16;
Ok(val1 * BASE + val2)
}
pub fn from_u16(id: u16) -> Result<String, &'static str> {
if id > MAX_ID {
return Err("Input number is out of the valid range (0-8835).");
}
let val1 = id / BASE;
let val2 = id % BASE;
let c1 = (val1 as u8 + OFFSET) as char;
let c2 = (val2 as u8 + OFFSET) as char;
Ok(format!("{}{}", c1, c2))
}
pub fn increment(id: u16) -> u16 {
(id + 1) % (MAX_ID + 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_msg_id_to_u16_valid() {
assert_eq!(to_u16("!!"), Ok(0));
assert_eq!(to_u16("!\""), Ok(1));
assert_eq!(to_u16("\"!"), Ok(BASE));
assert_eq!(to_u16("~~"), Ok(MAX_ID));
}
#[test]
fn test_msg_id_to_u16_invalid_length() {
assert!(to_u16("!").is_err());
assert!(to_u16("!!!").is_err());
}
#[test]
fn test_msg_id_to_u16_invalid_chars() {
assert!(to_u16(" !").is_err()); }
#[test]
fn test_msg_id_from_u16_valid() {
assert_eq!(from_u16(0), Ok("!!".to_string()));
assert_eq!(from_u16(1), Ok("!\"".to_string()));
assert_eq!(from_u16(BASE), Ok("\"!".to_string()));
assert_eq!(from_u16(MAX_ID), Ok("~~".to_string()));
}
#[test]
fn test_msg_id_from_u16_out_of_range() {
assert!(from_u16(MAX_ID + 1).is_err());
}
#[test]
fn test_msg_id_increment() {
assert_eq!(increment(0), 1);
assert_eq!(increment(MAX_ID), 0); assert_eq!(increment(100), 101);
}
}
}
pub struct PkVHashmapWrapper {
hashmap: std::collections::HashMap<String, (RefCell<Vec<u8>>, Box<dyn Fn(Vec<u8>) -> ()>)>,
}
impl crate::PkVariableAccessor for PkVHashmapWrapper {
fn get(&self, key: String) -> Option<Vec<u8>> {
self.hashmap.get(&key).map(|v| v.0.borrow().clone())
}
fn set(&self, key: String, value: Vec<u8>) -> Result<(), String> {
if self.hashmap.contains_key(&key) {
let v = self.hashmap.get(&key).unwrap();
v.0.replace(value.clone());
v.1(value);
Ok(())
} else {
Err(String::from("Key not found"))
}
}
}
impl PkVHashmapWrapper {
pub fn new(init_vec: Vec<(String, Option<Vec<u8>>, Box<dyn Fn(Vec<u8>) -> ()>)>) -> Self {
let mut hashmap = std::collections::HashMap::new();
for i in init_vec.into_iter() {
let (key, value, listener) = i;
hashmap.insert(key, (RefCell::new(value.unwrap_or_default()), listener));
}
PkVHashmapWrapper { hashmap }
}
}
pub struct PkMHashmapWrapper {
hashmap:
std::collections::HashMap<String, Box<dyn Fn(Option<Vec<u8>>) -> Pin<Box<dyn Pollable>>>>,
}
impl crate::PkMethodAccessor for PkMHashmapWrapper {
fn call(&self, key: String, param: Vec<u8>) -> Result<Pin<Box<dyn Pollable>>, String> {
if self.hashmap.contains_key(&key) {
let f = self.hashmap.get(&key).unwrap();
Ok(f(Some(param)))
} else {
Err(String::from("Method not found"))
}
}
}
impl PkMHashmapWrapper {
pub fn new(
init_vec: Vec<(
String,
Box<dyn Fn(Option<Vec<u8>>) -> Pin<Box<dyn Pollable>>>,
)>,
) -> Self {
let mut hashmap = std::collections::HashMap::new();
for i in init_vec.into_iter() {
let (key, method) = i;
hashmap.insert(key, method);
}
PkMHashmapWrapper { hashmap }
}
}
#[derive(Clone)]
pub struct PkPollable {
return_value: Arc<RwLock<Option<Vec<u8>>>>,
}
impl PkPollable {
pub fn execute<T>(function: T) -> Pin<Box<Self>>
where
T: FnOnce(Box<dyn FnOnce(Vec<u8>) -> () + Send + 'static>) + Send + 'static,
{
let return_value_arc = Arc::new(RwLock::new(None));
let return_value_clone = return_value_arc.clone();
std::thread::spawn(move || {
let resolve: Box<dyn FnOnce(Vec<u8>) -> () + Send + 'static> =
Box::new(move |ret: Vec<u8>| {
*return_value_clone.write().unwrap() = Some(ret);
});
function(Box::new(resolve));
});
Box::pin(PkPollable {
return_value: return_value_arc,
})
}
}
impl Pollable for PkPollable {
fn poll(&self) -> std::task::Poll<Result<Option<Vec<u8>>, String>> {
let read_guard = self.return_value.read().unwrap();
match read_guard.as_ref() {
Some(data) => std::task::Poll::Ready(Ok(Some(data.clone()))),
None => std::task::Poll::Pending,
}
}
}