Skip to content

Instantly share code, notes, and snippets.

@pythonesque
Last active August 29, 2015 14:10
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 pythonesque/fc43fe529adf8ddc26cb to your computer and use it in GitHub Desktop.
Save pythonesque/fc43fe529adf8ddc26cb to your computer and use it in GitHub Desktop.
#![feature(rustc_private,std_misc)]
extern crate arena;
use arena::TypedArena;
use std::cell::Cell;
use std::collections::hash_map::Entry as h;
use std::collections::HashMap;
use std::default::Default;
use std::fmt;
struct GraphRoot<'a> {
// Arena of any names we might need to allocate
//names: TypedArena<&'a str>,
// Arena of all the nodes in the graph
nodes: TypedArena<Node<'a>>,
}
impl<'a> GraphRoot<'a> {
pub fn new() -> GraphRoot<'a> {
GraphRoot {
//names: TypedArena::new(),
nodes: TypedArena::new(),
}
}
}
struct Graph<'a> {
root: &'a GraphRoot<'a>,
// A lookup table to map from string to node name
lookup: HashMap<&'a str, &'a Node<'a>>,
// Lookup table for any node names that haven't been found yet.
unbound: HashMap<&'a str, Vec<&'a Ref<'a>>>
}
impl<'a> Graph<'a> {
pub fn new(root: &'a GraphRoot<'a>) -> Graph<'a> {
Graph {
root: root,
lookup: HashMap::new(),
unbound: HashMap::new(),
}
}
pub fn add<'b>(&'b mut self, node: Node<'a>) -> &'a Node<'a> {
let node = &*self.root.nodes.alloc(node);
// First, replace any nodes this one references with the appropriate
// reference, and add those that haven't been bound yet to the unbound
// table.
for noderef in node.out().iter() {
if let NodeReference::NameRef(name) = noderef.get() {
if let Some(&node) = self.lookup.get(&name) {
// Found the name in the lookup table, replace it
noderef.set(NodeReference::NodeRef(node));
} else {
// The name hasn't been found yet, so add it to the unbound
// table
match self.unbound.entry(name) {
h::Occupied(mut o) => { o.get_mut().push(noderef); }, // add an entry,
h::Vacant(v) => { v.insert(vec![noderef]); } // initialize a new list
}
}
}
}
// Add this node to the lookup table.
if let Some(name) = node.name {
self.lookup.insert(&*name, node);
// Finally, properly rebind any nodes that haven't been bound yet and are
// looking for the current node.
if let Some(noderefs) = self.unbound.remove(&name) {
for noderef in noderefs.iter() {
noderef.set(NodeReference::NodeRef(node));
}
}
}
node
}
}
#[derive(Copy,Debug)]
enum NodeReference<'a> {
NodeRef(&'a Node<'a>),
NameRef(&'a str),
}
fn named<'a>(name: &'a str) -> Ref<'a> {
Cell::new(NodeReference::NameRef(name))
}
type Ref<'a> = Cell<NodeReference<'a>>;
#[derive(Debug)]
struct Context; // Imagine we put the context in here
#[derive(Debug)]
struct Node<'a> {
// Name of node
pub name: Option<&'a str>,
// The actual node operation
pub op: Operation<'a>,
}
impl<'a> Node<'a> {
fn out<'b>(&'b self) -> &'b [Ref<'a>] {
match self.op {
Operation::SourceOp(Source { ref emits, .. }) => &**emits,
Operation::EachOp(Each { ref emits, .. }) => &**emits,
}
}
}
#[derive(Debug)]
enum EndCyclePolicy {
NullEmit,
#[allow(dead_code)] Explicit,
}
impl Default for EndCyclePolicy {
fn default() -> EndCyclePolicy { EndCyclePolicy::NullEmit }
}
struct Source<'a> {
// End cycle policy,
pub end_cycle_policy: EndCyclePolicy,
pub begin_cycle: Box<FnMut(&mut Context)>,
// Function yielding the next tuple
pub next_tuple: Box<FnMut(&mut Context)>,
// List of nodes that are being emitted by this one
pub emits: Vec<Ref<'a>>,
}
impl<'a> fmt::Debug for Source<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Source {{ end_cycle_policy: {:?}, emits: {:?} }}", self.end_cycle_policy, self.emits)
}
}
#[derive(Debug)]
enum OutputFormat {
Replace,
Merge,
}
impl Default for OutputFormat {
fn default() -> OutputFormat { OutputFormat::Replace }
}
struct Each<'a> {
// Output format
pub output_format: OutputFormat,
pub prepare: Box<FnMut(&mut Context)>,
// Function yielding the next tuple
pub execute: Box<FnMut(&mut Context)>,
// List of nodes that are being emitted by this one
pub emits: Vec<Ref<'a>>,
}
impl<'a> fmt::Debug for Each<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Each {{ output_format: {:?}, emits: {:?} }}", self.output_format, self.emits)
}
}
#[derive(Debug)]
enum Operation<'a> {
SourceOp(Source<'a>),
EachOp(Each<'a>),
}
fn main() {
let storage = GraphRoot::new();
let mut graph = Graph::new(&storage);
let source = graph.add(Node {
name: Some("source"),
op: Operation::SourceOp(Source {
end_cycle_policy: Default::default(),
begin_cycle: Box::new(|ctx| {
println!("Beginning cycle in {:?}", ctx)
}),
next_tuple: Box::new(|ctx| {
println!("Next tuple for {:?}", ctx)
}),
emits: vec![named("each1"), named("each2")],
})
});
graph.add(Node {
name: Some("each1"),
op: Operation::EachOp(Each {
output_format: OutputFormat::Merge,
prepare: Box::new(|ctx| {
println!("Preparing each in {:?}", ctx)
}),
execute: Box::new(|ctx| {
println!("Executing each in {:?}", ctx)
}),
emits: vec![],
})
});
println!("{:?}", source);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment