Browse Source

Rust: progress with outputting events

Joeri Exelmans 4 years ago
parent
commit
eaa910e05e
3 changed files with 43 additions and 44 deletions
  1. 26 26
      src/sccd/cd/codegen/sccdlib.rs
  2. 8 8
      src/sccd/statechart/codegen/rust.py
  3. 9 10
      src/sccd/test/codegen/rust.py

+ 26 - 26
src/sccd/cd/codegen/sccdlib.rs

@@ -3,57 +3,57 @@ use std::collections::binary_heap::PeekMut;
 use std::cmp::Ordering;
 
 type Timestamp = usize; // unsigned integer, platform's word size
-type OutputCallback = fn(&str, &str);
+// type OutputCallback = fn(&str, &str);
 
-pub trait State {
-  fn enter_actions(output: OutputCallback);
-  fn exit_actions(output: OutputCallback);
-  fn enter_default(output: OutputCallback);
+pub trait State<OutputCallback> {
+  fn enter_actions(output: &mut OutputCallback);
+  fn exit_actions(output: &mut OutputCallback);
+  fn enter_default(output: &mut OutputCallback);
 
-  fn exit_current(&self, output: OutputCallback);
+  fn exit_current(&self, output: &mut OutputCallback);
 }
 
-pub trait SC<EventType> {
-  fn init(&self, output: OutputCallback);
-  fn fair_step(&mut self, event: Option<EventType>, output: OutputCallback);
+pub trait SC<EventType, OutputCallback> {
+  fn init(&self, output: &mut OutputCallback);
+  fn fair_step(&mut self, event: Option<EventType>, output: &mut OutputCallback);
 }
 
-pub enum Target<'a, EventType> {
-  Narrowcast(&'a mut dyn SC<EventType>),
+pub enum Target<'a, EventType, OutputCallback> {
+  Narrowcast(&'a mut dyn SC<EventType, OutputCallback>),
   Broadcast,
 }
 
-pub struct Entry<'a, EventType> {
+pub struct Entry<'a, EventType, OutputCallback> {
   timestamp: Timestamp,
   event: EventType,
-  target: Target<'a, EventType>,
+  target: Target<'a, EventType, OutputCallback>,
 }
 
-impl<'a, EventType> Ord for Entry<'a, EventType> {
+impl<'a, EventType, OutputCallback> Ord for Entry<'a, EventType, OutputCallback> {
   fn cmp(&self, other: &Self) -> Ordering {
     self.timestamp.cmp(&other.timestamp).reverse()
   }
 }
 
-impl<'a, EventType> PartialOrd for Entry<'a, EventType> {
+impl<'a, EventType, OutputCallback> PartialOrd for Entry<'a, EventType, OutputCallback> {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         Some(self.cmp(other))
     }
 }
 
-impl<'a, EventType> PartialEq for Entry<'a, EventType> {
+impl<'a, EventType, OutputCallback> PartialEq for Entry<'a, EventType, OutputCallback> {
     fn eq(&self, other: &Self) -> bool {
         self.timestamp == other.timestamp
     }
 }
 
-impl<'a, EventType> Eq for Entry<'a, EventType> {}
+impl<'a, EventType, OutputCallback> Eq for Entry<'a, EventType, OutputCallback> {}
 
 
-pub struct Controller<'a, EventType> {
-  queue: BinaryHeap<Entry<'a, EventType>>,
+pub struct Controller<'a, EventType, OutputCallback> {
+  queue: BinaryHeap<Entry<'a, EventType, OutputCallback>>,
   simtime: Timestamp,
-  output_callback: fn(&str, &str),
+  output: OutputCallback,
 }
 
 // impl<'a, EventType> Default for Controller<'a, EventType> {
@@ -70,15 +70,15 @@ pub enum Until {
   Eternity,
 }
 
-impl<'a, EventType: Copy> Controller<'a, EventType> {
-  fn new(output_callback: fn(&str, &str)) -> Self {
+impl<'a, EventType: Copy, OutputCallback: FnMut(&'static str, &'static str)> Controller<'a, EventType, OutputCallback> {
+  fn new(output: OutputCallback) -> Self {
     Self {
       queue: BinaryHeap::new(),
       simtime: 0,
-      output_callback,
+      output,
     }
   }
-  fn add_input(&mut self, entry: Entry<'a, EventType>) {
+  fn add_input(&mut self, entry: Entry<'a, EventType, OutputCallback>) {
     self.queue.push(entry);
   }
   fn run_until(&mut self, until: Until) {
@@ -99,14 +99,14 @@ impl<'a, EventType: Copy> Controller<'a, EventType> {
 
           match &mut entry.target {
             Target::Narrowcast(sc) => {
-              sc.fair_step(Some(e), self.output_callback);
+              sc.fair_step(Some(e), &mut self.output);
             },
             Target::Broadcast => {
               println!("broadcast not implemented!")
             },
           };
 
-          PeekMut::<'_, Entry<'a, EventType>>::pop(entry);
+          PeekMut::<'_, Entry<'a, EventType, OutputCallback>>::pop(entry);
         },
         None => { break 'running; },
       }

+ 8 - 8
src/sccd/statechart/codegen/rust.py

@@ -145,23 +145,23 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
         if isinstance(state, HistoryState):
             return None # we got no time for pseudo-states!
 
-        w.writeln("impl State for %s {" % ident_type(state))
+        w.writeln("impl<OutputCallback: FnMut(&'static str, &'static str)> State<OutputCallback> for %s {" % ident_type(state))
 
-        w.writeln("  fn enter_actions(output: OutputCallback) {")
+        w.writeln("  fn enter_actions(output: &mut OutputCallback) {")
         w.writeln("    println!(\"enter %s\");" % state.opt.full_name);
         w.indent(); w.indent()
         compile_actions(state.enter, w)
         w.dedent(); w.dedent()
         w.writeln("  }")
 
-        w.writeln("  fn exit_actions(output: OutputCallback) {")
+        w.writeln("  fn exit_actions(output: &mut OutputCallback) {")
         w.writeln("    println!(\"exit %s\");" % state.opt.full_name);
         w.indent(); w.indent()
         compile_actions(state.exit, w)
         w.dedent(); w.dedent()
         w.writeln("  }")
 
-        w.writeln("  fn enter_default(output: OutputCallback) {")
+        w.writeln("  fn enter_default(output: &mut OutputCallback) {")
         w.writeln("    %s::enter_actions(output);" % ident_type(state))
         if isinstance(state, ParallelState):
             for child in children:
@@ -171,7 +171,7 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
                 w.writeln("    %s::enter_default(output);" % ident_type(state.default_state))
         w.writeln("  }")
 
-        w.writeln("  fn exit_current(&self, output: OutputCallback) {")
+        w.writeln("  fn exit_current(&self, output: &mut OutputCallback) {")
         if isinstance(state, ParallelState):
             for child in children:
                 w.writeln("    self.%s.exit_current(output);" % ident_field(child));
@@ -223,11 +223,11 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
     w.writeln("}")
     w.writeln()
 
-    w.writeln("impl SC<Event> for Statechart {")
-    w.writeln("  fn init(&self, output: OutputCallback) {")
+    w.writeln("impl<OutputCallback: FnMut(&'static str, &'static str)> SC<Event, OutputCallback> for Statechart {")
+    w.writeln("  fn init(&self, output: &mut OutputCallback) {")
     w.writeln("    %s::enter_default(output);" % ident_type(tree.root))
     w.writeln("  }")
-    w.writeln("  fn fair_step(&mut self, event: Option<Event>, output: OutputCallback) {")
+    w.writeln("  fn fair_step(&mut self, event: Option<Event>, output: &mut OutputCallback) {")
     w.writeln("    println!(\"fair step\");")
     w.writeln("    let %s = &mut self.current_state;" % ident_var(tree.root))
 

+ 9 - 10
src/sccd/test/codegen/rust.py

@@ -20,24 +20,23 @@ def compile_test(variants: List[TestVariant], w: IndentingWriter):
     w.writeln("fn main() {")
     w.indent()
 
-    for v in variants:
-        w.writeln("// Test variant")
-        # w.writeln("let mut raised = Vec::<&str>::new();")
-        # w.writeln("let output = |port, event| {")
-        w.writeln("fn output(port: &str, event: &str) {")
+    for n, v in enumerate(variants):
+        w.writeln("// Test variant %d" % n)
+        w.writeln("let mut raised = Vec::<&str>::new();")
+        w.writeln("let mut output = |port, event| {")
         w.writeln("  println!(\"^{}:{}\", port, event);")
-        # w.writeln("  raised.push(event);")
-        w.writeln("}")
-        w.writeln("let mut controller = Controller::<Event>::new(output);")
+        w.writeln("  raised.push(event); return;")
+        w.writeln("};")
         w.writeln("let mut sc: Statechart = Default::default();")
-        w.writeln("sc.init(output);")
+        w.writeln("sc.init(&mut output);")
+        w.writeln("let mut controller = Controller::<Event, _>::new(output);")
         for i in v.input:
             if len(i.events) > 1:
                 raise Exception("Multiple simultaneous input events not supported")
             elif len(i.events) == 0:
                 raise Exception("Test declares empty bag of input events - not supported")
 
-            w.writeln("controller.add_input(Entry::<Event>{")
+            w.writeln("controller.add_input(Entry::<Event, _>{")
             w.writeln("  timestamp: %d," % i.timestamp.opt)
             w.writeln("  event: Event::%s," % i.events[0].name)
             w.writeln("  target: Target::Narrowcast(&mut sc),")