use crate::{L2Device, L3Device, Result};
use std::sync::Arc;
pub type Cleanup = Box<dyn FnOnce() -> Result<()> + Send>;
pub trait L2Acceptor {
fn accept_l2(&self) -> Result<Arc<dyn L2Device>>;
}
pub trait L2Connector {
fn connect_l2(&self, dev: Arc<dyn L2Device>) -> Result<Cleanup>;
}
pub trait L3Connector {
fn connect_l3(&self, dev: Arc<dyn L3Device>) -> Result<Cleanup>;
}
pub trait DoneSignal {
fn wait_done(&self);
}
pub fn serve(acceptor: &dyn L2Acceptor, connector: &dyn L2Connector) -> Result<()> {
loop {
let dev = acceptor.accept_l2()?;
let cleanup = match connector.connect_l2(dev.clone()) {
Ok(c) => c,
Err(_) => {
let _ = dev.close();
continue;
}
};
if let Some(d) = downcast_done(&dev) {
std::thread::spawn(move || {
d.wait_done();
let _ = cleanup();
});
} else {
std::mem::forget(cleanup);
}
}
}
fn downcast_done(_dev: &Arc<dyn L2Device>) -> Option<Arc<dyn DoneSignalThread>> {
None
}
trait DoneSignalThread: Send + Sync + 'static {
fn wait_done(self: Arc<Self>);
}
pub fn serve_with_done<A>(acceptor: &A, connector: &dyn L2Connector) -> Result<()>
where
A: L2AcceptorWithDone + ?Sized,
{
loop {
let (dev, done) = acceptor.accept_l2_with_done()?;
let cleanup = match connector.connect_l2(dev.clone()) {
Ok(c) => c,
Err(_) => {
let _ = dev.close();
continue;
}
};
if let Some(done) = done {
std::thread::spawn(move || {
done.wait();
let _ = cleanup();
});
} else {
std::mem::forget(cleanup);
}
}
}
pub trait L2AcceptorWithDone {
fn accept_l2_with_done(&self) -> Result<(Arc<dyn L2Device>, Option<Box<dyn Done + Send>>)>;
}
pub trait Done {
fn wait(self: Box<Self>);
}