Я не думаю, что это возможно сделать напрямую, но если ваш тип T может быть сериализован, то вот способ. Пусть listeners
будет Vec<Arc<dyn Fn(String)>>
, и при вставке в этот Ve c передайте лямбда, которая преобразует String в T и вызывает фактическую функцию прослушивателя. Вот рабочий код того, что я имею в виду:
use std::sync::Arc;
struct EventEmitter {
listeners: Vec<Arc<dyn Fn(String)>>,
}
impl EventEmitter {
pub fn add_listener<T>(&mut self, listener: Arc<dyn Fn(T)>)
where
T: std::str::FromStr, // So that `s` can be converted to type `t`.
<T as std::str::FromStr>::Err: std::fmt::Debug, // So that `e` can be printed.
T: 'static, // See https://stackoverflow.com/a/29740792/8111265
{
self.listeners.push(Arc::new(move |s| {
match s.parse::<T>() {
Ok(t) => listener(t),
Err(e) => println!("Oops! we couldn't convert {:?} to type T due to {:?}", s, e),
};
}));
}
pub fn notify(&self, s: &str) {
for listener in self.listeners.iter() {
listener(s.to_string());
}
}
}
#[test]
fn test_event_emitter() {
let mut e = EventEmitter { listeners: vec![] };
// i32 implements `std::str::FromStr`.
e.add_listener(Arc::new(|x: i32| {
println!("Got {:?} in i32 listener", x);
}));
// std::net::IpAddr implements `std::str::FromStr`.
e.add_listener(Arc::new(|ip_addr: std::net::IpAddr| {
println!("Got {:?} in IpAddr listener", ip_addr);
}));
// This line prints:
// Got 42 in i32 listener
// Oops! we couldn't convert "42" to type T due to AddrParseError(())
e.notify("42");
// This line prints:
// Oops! we couldn't convert "127.0.0.1" to type T due to ParseIntError { kind: InvalidDigit }
// Got V4(127.0.0.1) in IpAddr listener
e.notify("127.0.0.1");
}
Идею можно еще немного уточнить: возможно, некоторые Arc
не понадобятся, и, возможно, есть лучший «базовый» тип, чем String (возможно, это можно сделать для работы с любым типом, который работает с serde), вы можете использовать &str
вместо String как есть.
Поскольку вы спрашивали об использовании serde, вот пример:
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct PointInts {
x: i32,
y: i32,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct PointFloats {
x: f32,
y: f32,
}
struct EventEmitter {
listeners: Vec<Arc<dyn Fn(&[u8])>>,
}
impl EventEmitter {
pub fn add_listener<T>(&mut self, listener: Arc<dyn Fn(T)>)
where
T: serde::de::DeserializeOwned,
T: 'static, // See https://stackoverflow.com/a/29740792/8111265
{
self.listeners.push(Arc::new(move |bytes| {
match bincode::deserialize(bytes) {
Ok(t) => listener(t),
Err(e) => println!(
"Oops! we couldn't convert the bytes {:?} to type T due to {:?}",
bytes, e
),
};
}));
}
pub fn notify<T>(&self, obj: T)
where
T: serde::Serialize,
{
let bytes = bincode::serialize(&obj).unwrap();
for listener in self.listeners.iter() {
listener(&bytes);
}
}
}
#[test]
fn test_event_emitter() {
let mut e = EventEmitter { listeners: vec![] };
// PoinitInts implements Serialize and Deserialize.
e.add_listener(Arc::new(|p: PointInts| {
println!("Got {:?} in PointInts listener", p);
}));
// PointFloats implements Serialize and Deserialize.
e.add_listener(Arc::new(|p: PointFloats| {
println!("Got {:?} in PointFloats listener", p);
}));
// This line prints:
// Got PointInts { x: 42, y: 999 } in PointInts listener
// Got PointFloats { x: 0.000000000000000000000000000000000000000000059, y: 0.0000000000000000000000000000000000000000014 } in PointFloats listener
e.notify(PointInts { x: 42, y: 999 });
// This line prints:
// Got PointInts { x: 1109917696, y: 1120327434 } in PointInts listener
// Got PointFloats { x: 42.0, y: 99.42 } in PointFloats listener
e.notify(PointFloats { x: 42.0, y: 99.420 });
}
Обратите внимание, что bincode::deserialize
вернет Ok(_)
, если байты могут быть преобразованы в заданную запрошенную структуру, и, следовательно, почему вы видите странные значения выше (может быть способ добавить тег типа, чтобы 'неправильные' структуры не десериализуются).