Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created August 20, 2019 23:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rust-play/8ec4f34492e292ca50595ecc7ea02983 to your computer and use it in GitHub Desktop.
Save rust-play/8ec4f34492e292ca50595ecc7ea02983 to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
use std::collections::HashMap;
pub type DidWork = bool;
pub type RequestId = String;
pub struct PsCore<'pscore, MOD, OUT, OUTR, INR, E> {
pending_outs: HashMap<RequestId, Box<dyn Fn(&mut MOD, OUTR) + 'pscore>>,
out_outbox: Vec<(Option<RequestId>, OUT)>,
in_outbox: Vec<(RequestId, INR)>,
phantom_error: std::marker::PhantomData<E>,
}
impl<'pscore, MOD, OUT, OUTR, INR, E> PsCore<'pscore, MOD, OUT, OUTR, INR, E> {
pub fn new() -> Self {
Self {
pending_outs: HashMap::new(),
out_outbox: Vec::new(),
in_outbox: Vec::new(),
phantom_error: std::marker::PhantomData,
}
}
pub fn process(&mut self) -> Result<DidWork, E> {
Ok(true)
}
pub fn send_out_request(&mut self, request: OUT, cb: Box<dyn Fn(&mut MOD, OUTR) + 'pscore>) {
let request_id = "".to_string();
self.pending_outs.insert(request_id.clone(), cb);
self.out_outbox.push((Some(request_id), request));
}
pub fn handle_out_response(&mut self, m: &mut MOD, request_id: RequestId, response: OUTR) {
match self.pending_outs.remove(&request_id) {
None => println!("no pending for request_id {}", request_id),
Some(cb) => {
cb(m, response)
}
}
}
pub fn post_in_response(&mut self, request_id: RequestId, response: INR) {
self.in_outbox.push((request_id, response));
}
pub fn drain_requests(&mut self) -> Vec<(Option<RequestId>, OUT)> {
self.out_outbox.drain(..).collect()
}
pub fn drain_responses(&mut self) -> Vec<(RequestId, INR)> {
self.in_outbox.drain(..).collect()
}
}
pub trait PsModule<'pmod, MOD, OUT, OUTR, IN, INR, E> {
fn as_mut(&mut self) -> &mut MOD;
fn get_core(&mut self) -> &mut PsCore<'pmod, MOD, OUT, OUTR, INR, E>;
fn take_core(&mut self) -> PsCore<'pmod, MOD, OUT, OUTR, INR, E>;
fn put_core(&mut self, core: PsCore<'pmod, MOD, OUT, OUTR, INR, E>);
fn process(&mut self) -> Result<DidWork, E> {
self.get_core().process()
}
fn request(&mut self, request_id: Option<RequestId>, request: IN);
fn respond(&mut self, request_id: RequestId, response: OUTR) {
let mut core = self.take_core();
core.handle_out_response(self.as_mut(), request_id, response);
self.put_core(core);
}
fn drain_requests(&mut self) -> Vec<(Option<RequestId>, OUT)> {
self.get_core().drain_requests()
}
fn drain_responses(&mut self) -> Vec<(RequestId, INR)> {
self.get_core().drain_responses()
}
}
#[derive(Debug)]
pub struct CError(pub String);
#[derive(Debug)]
pub struct COut(pub String);
#[derive(Debug)]
pub struct COutR(pub String);
#[derive(Debug)]
pub struct CIn(pub String);
#[derive(Debug)]
pub struct CInR(pub String);
pub struct CryptoTransport<'ct> {
core: Option<PsCore<'ct, CryptoTransport<'ct>, COut, COutR, CInR, CError>>,
inner: Vec<String>,
}
impl<'ct> CryptoTransport<'ct> {
pub fn new() -> Self {
Self {
core: Some(PsCore::new()),
inner: Vec::new(),
}
}
pub fn print_inner(&self) {
println!("ct inner: {:?}", self.inner);
}
}
impl<'ct> PsModule<'ct, CryptoTransport<'ct>, COut, COutR, CIn, CInR, CError> for CryptoTransport<'ct> {
fn as_mut(&mut self) -> &mut CryptoTransport<'ct> {
&mut *self
}
fn get_core(&mut self) -> &mut PsCore<'ct, CryptoTransport<'ct>, COut, COutR, CInR, CError> {
self.core.as_mut().unwrap()
}
fn take_core(&mut self) -> PsCore<'ct, CryptoTransport<'ct>, COut, COutR, CInR, CError> {
std::mem::replace(&mut self.core, None).unwrap()
}
fn put_core(&mut self, core: PsCore<'ct, CryptoTransport<'ct>, COut, COutR, CInR, CError>) {
std::mem::replace(&mut self.core, Some(core));
}
fn process(&mut self) -> Result<DidWork, CError> {
self.get_core().send_out_request(COut("test_out_request".to_string()), Box::new(|m, r| {
m.inner.push(r.0);
}));
self.get_core().process()
}
fn request(&mut self, request_id: Option<RequestId>, request: CIn) {
self.inner.push(request.0);
if let Some(request_id) = request_id {
self.get_core().post_in_response(request_id, CInR("responding".to_string()));
}
}
}
pub fn main() {
let mut ct = CryptoTransport::new();
// process will generate an outgoing request of us
ct.process().unwrap();
println!("req: {:?}", ct.drain_requests());
// that request has a request_id of "", let's respond to it:
ct.respond("".to_string(), COutR("test-resp".to_string()));
// make sure the ct inner state was updated
ct.print_inner();
// now, let's make a request of ct
ct.request(Some("zz".to_string()), CIn("test-req".to_string()));
// was it posted?
ct.print_inner();
// see if we get a response
println!("resp: {:?}", ct.drain_responses());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment