use table::{Table, TableId, Value, Index};
use indexes::Hasher;
#[cfg(feature = "no-std")] use alloc::fmt;
#[cfg(feature = "no-std")] use alloc::string::String;
#[cfg(feature = "no-std")] use alloc::vec::Vec;
#[cfg(not(feature = "no-std"))] use core::fmt;
use database::{Transaction, Interner, Change};
use hashbrown::hash_map::{HashMap, Entry};
use hashbrown::hash_set::HashSet;
use indexes::TableIndex;
use operations;
use operations::{set_any, table_vertical_concatenate, table_horizontal_concatenate, logic_and, logic_or, table_range, stat_sum, math_add, math_subtract, math_multiply, math_divide, compare_equal, compare_greater_than, compare_greater_than_equal, compare_less_than, compare_less_than_equal, compare_not_equal, Parameter};
use quantities::{Quantity, ToQuantity, QuantityMath, make_quantity};
use errors::{Error, ErrorType};
#[derive(Clone)]
pub struct Runtime {
pub blocks: HashMap<usize, Block>,
pub pipes_map: HashMap<Register, HashSet<Address>>,
pub tables_map: HashMap<u64, u64>,
pub ready_blocks: HashSet<usize>,
pub functions: HashMap<String, Option<extern "C" fn(Vec<(String, Table)>)->Table>>,
pub changed_this_round: HashSet<(u64, Index)>,
pub errors: Vec<Error>,
}
impl Runtime {
pub fn new() -> Runtime {
let mut runtime = Runtime {
blocks: HashMap::new(),
ready_blocks: HashSet::new(),
pipes_map: HashMap::new(),
tables_map: HashMap::new(),
functions: HashMap::new(),
changed_this_round: HashSet::new(),
errors: Vec::new(),
};
runtime.functions.insert("math/add".to_string(),Some(math_add));
runtime.functions.insert("math/multiply".to_string(),Some(math_multiply));
runtime.functions.insert("math/divide".to_string(),Some(math_divide));
runtime.functions.insert("math/subtract".to_string(),Some(math_subtract));
runtime.functions.insert("compare/greater-than".to_string(),Some(compare_greater_than));
runtime.functions.insert("compare/less-than".to_string(),Some(compare_less_than));
runtime.functions.insert("compare/greater-than-equal".to_string(),Some(compare_greater_than_equal));
runtime.functions.insert("compare/less-than-equal".to_string(),Some(compare_less_than_equal));
runtime.functions.insert("compare/equal".to_string(),Some(compare_equal));
runtime.functions.insert("compare/not-equal".to_string(),Some(compare_not_equal));
runtime.functions.insert("stat/sum".to_string(),Some(stat_sum));
runtime.functions.insert("table/range".to_string(),Some(table_range));
runtime.functions.insert("logic/and".to_string(),Some(logic_and));
runtime.functions.insert("logic/or".to_string(),Some(logic_or));
runtime.functions.insert("table/horizontal-concatenate".to_string(),Some(table_horizontal_concatenate));
runtime.functions.insert("table/vertical-concatenate".to_string(),Some(table_vertical_concatenate));
runtime.functions.insert("set/any".to_string(),Some(set_any));
runtime
}
pub fn clear(&mut self) {
self.blocks.clear();
self.ready_blocks.clear();
self.pipes_map.clear();
}
pub fn register_block(&mut self, mut block: Block, store: &mut Interner) {
if block.id == 0 {
block.id = self.blocks.len() + 1;
}
for register in block.input_registers.iter() {
let table = register.table;
let column = register.column.clone();
let new_address = Address{block: block.id, register: register.clone()};
let listeners = self.pipes_map.entry(register.clone()).or_insert(HashSet::new());
listeners.insert(new_address);
}
for fun in &block.functions {
self.functions.entry(fun.to_string()).or_insert(None);
}
for local_table in block.memory.map.keys() {
self.tables_map.insert(*local_table, block.id as u64);
}
self.errors.append(&mut block.errors.clone());
if block.updated && block.input_registers.len() == 0 && block.errors.len() == 0 {
self.ready_blocks.insert(block.id);
}
self.blocks.insert(block.id, block.clone());
}
pub fn register_blocks(&mut self, blocks: Vec<Block>, store: &mut Interner) {
for block in blocks {
self.register_block(block, store);
}
}
pub fn remove_block(&mut self, block_id: &usize) {
{
let block = self.blocks.get(block_id).unwrap();
for register in block.input_registers.iter() {
let mut listeners = self.pipes_map.get_mut(®ister).unwrap();
let address = Address{block: block_id.clone(), register: register.clone()};
listeners.remove(&address);
}
for local_table in block.memory.map.keys() {
self.tables_map.remove(local_table);
}
self.ready_blocks.remove(block_id);
}
self.blocks.remove(&block_id);
}
pub fn run_network(&mut self, store: &mut Interner, max_iterations: u64) {
let mut iteration_count = 0;
while {
let mut ready_blocks: Vec<usize> = self.ready_blocks.drain().map(|arg| {
arg.clone()
}).collect::<Vec<usize>>();
ready_blocks.sort();
for block_id in ready_blocks {
let block = &mut self.blocks.get_mut(&block_id).unwrap();
block.solve(store, &self.functions);
for register in block.input_registers.iter() {
let table = register.table;
let column = register.column.clone();
let new_address = Address{block: block.id, register: register.clone()};
let listeners = self.pipes_map.entry(register.clone()).or_insert(HashSet::new());
listeners.insert(new_address);
}
}
for (table, column) in store.tables.changed_this_round.drain() {
self.changed_this_round.insert((table.clone(), column.clone()));
let register = Register::new(TableId::Global(table),column);
match self.pipes_map.get(®ister) {
Some(register_addresses) => {
for register_address in register_addresses.iter() {
let mut block = &mut self.blocks.get_mut(®ister_address.block).unwrap();
block.ready.insert(register_address.register.clone());
if block.is_ready() {
self.ready_blocks.insert(register_address.block);
}
}
},
_ => (),
}
}
iteration_count += 1;
if iteration_count == max_iterations {
self.ready_blocks.clear();
}
!self.ready_blocks.is_empty()
} {}
for mut block in &mut self.blocks.values_mut() {
block.updated = false;
}
}
}
impl fmt::Debug for Runtime {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Runtime:\n").unwrap();
write!(f, " Blocks:\n\n").unwrap();
for ref block in &self.blocks {
write!(f, "{:?}\n\n", block).unwrap();
}
Ok(())
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Address {
pub block: usize,
pub register: Register,
}
impl fmt::Debug for Address {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "@(block: {:?}, register: {:?})", self.block, self.register)
}
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct Register {
pub table: TableId,
pub column: Index,
}
impl Register {
pub fn new(table: TableId, column: Index) -> Register {
Register {
table: table,
column: column,
}
}
}
impl fmt::Debug for Register {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?}, {:?})", self.table, self.column)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BlockState {
Ready,
Error,
Unsatisfied,
Updated,
Pending,
Disabled,
New,
}
#[derive(Clone, PartialEq)]
pub struct Block {
pub id: usize,
pub state: BlockState,
pub name: String,
pub text: String,
pub ready: HashSet<Register>,
pub updated: bool,
pub plan: Vec<Constraint>,
pub input_registers: HashSet<Register>,
pub output_registers: HashSet<Register>,
pub constraints: Vec<(String, Vec<Constraint>)>,
pub errors: Vec<Error>,
pub functions: HashSet<String>,
memory: TableIndex,
tables_modified: HashSet<u64>,
scratch: Table,
lhs_rows_empty: Vec<Value>,
lhs_columns_empty: Vec<Value>,
rhs_rows_empty: Vec<Value>,
rhs_columns_empty: Vec<Value>,
block_changes: Vec<Change>,
current_step: Option<Constraint>,
}
impl Block {
pub fn new() -> Block {
Block {
id: 0,
name: String::from(""),
text: String::from(""),
ready: HashSet::with_capacity(1),
state: BlockState::New,
updated: false,
plan: Vec::new(),
input_registers: HashSet::with_capacity(1),
output_registers: HashSet::with_capacity(1),
functions: HashSet::with_capacity(1),
constraints: Vec::with_capacity(1),
memory: TableIndex::new(1),
tables_modified: HashSet::new(),
errors: Vec::new(),
scratch: Table::new(0,0,0),
lhs_rows_empty: Vec::new(),
lhs_columns_empty: Vec::new(),
rhs_rows_empty: Vec::new(),
rhs_columns_empty: Vec::new(),
block_changes: Vec::new(),
current_step: None,
}
}
pub fn get_table(&self, table_id: u64) -> Option<&Table> {
self.memory.get(table_id)
}
pub fn add_constraints(&mut self, constraint_tuple: (String, Vec<Constraint>)) {
self.constraints.push(constraint_tuple.clone());
let (constraint_text, constraints) = constraint_tuple;
let mut reversed = constraints.clone();
reversed.reverse();
for constraint in reversed {
match constraint {
Constraint::Function{..} |
Constraint::CopyTable{..} |
Constraint::ChangeScan{..} |
Constraint::Append{..} |
Constraint::Scan{..} |
Constraint::Insert{..} => self.plan.push(constraint.clone()),
_ => (),
}
}
for (constraint_ix, constraint) in constraints.iter().enumerate() {
match constraint {
Constraint::CopyTable{from_table, to_table} => {
self.output_registers.insert(Register::new(TableId::Global(*to_table), Index::Index(0)));
},
Constraint::Append{from_table, to_table} => {
match to_table {
TableId::Global(id) => {
self.input_registers.insert(Register::new(*to_table, Index::Index(0)));
self.output_registers.insert(Register::new(*to_table, Index::Index(0)));
}
_ => (),
};
},
Constraint::Insert{from: (from_table, ..), to: (to_table, ..)} => {
match to_table {
TableId::Global(id) => {
self.input_registers.insert(Register::new(*to_table, Index::Index(0)));
self.output_registers.insert(Register::new(*to_table, Index::Index(0)));
},
_ => (),
};
},
Constraint::Scan{table, indices, output} => {
match table {
TableId::Global(id) => {
self.input_registers.insert(Register{table: *table, column: Index::Index(0)});
},
_ => (),
}
},
Constraint::ChangeScan{tables} => {
for (table, indices) in tables {
match (table, indices) {
(TableId::Global(id), x) => {
let column = match x[0] {
(None, Some(Parameter::Index(index))) => index,
_ => Index::Index(0),
};
self.input_registers.insert(Register{table: *table, column});
},
(TableId::Local(id), _) => {
self.input_registers.insert(Register{table: *table, column: Index::Index(0)});
},
_ => (),
}
}
},
Constraint::AliasTable{table, alias} => {
match table {
TableId::Local(id) => {
match self.memory.add_alias(*id, *alias) {
Err(mech_error) => {
self.errors.push(Error{
block: self.id as u64,
constraint: constraint.clone(),
error_id: mech_error,
});
},
_ => (),
}
},
TableId::Global(id) => (),
}
},
Constraint::Function{fnstring, parameters, output} => {
self.functions.insert(fnstring.to_string());
for (arg_name, table, indices) in parameters {
match (table, indices) {
(TableId::Global(id), x) => {
let column = match x[0] {
(None, Some(Parameter::Index(index))) => index,
_ => Index::Index(0),
};
self.input_registers.insert(Register{table: *table, column});
},
_ => (),
}
}
},
Constraint::NewTable{id, rows, columns} => {
match id {
TableId::Local(id) => {
self.memory.insert(Table::new(*id, *rows, *columns));
}
_ => (),
}
},
Constraint::Empty{table, row, column} => {
let table_id = match table {
TableId::Local(id) => *id,
_ => 0,
};
match self.memory.map.entry(table_id) {
Entry::Occupied(mut o) => {
let table_ref = o.get_mut();
table_ref.set_cell(&row, &column, Value::Empty);
},
Entry::Vacant(v) => {
},
};
self.updated = true;
},
Constraint::Constant{table, row, column, value, unit} => {
let (domain, scale) = match unit {
Some(unit_value) => match unit_value.as_ref() {
"g" => (1, 0),
"kg" => (1, 3),
"m" => (2, 0),
"km" => (2, 3),
_ => (0, 0),
},
_ => (0, 0),
};
let test = make_quantity(value.mantissa(), value.range() + scale, domain);
let table_id = match table {
TableId::Local(id) => *id,
_ => 0,
};
match self.memory.map.entry(table_id) {
Entry::Occupied(mut o) => {
let table_ref = o.get_mut();
table_ref.set_cell(&row, &column, Value::from_quantity(test));
},
Entry::Vacant(v) => {
},
};
self.updated = true;
},
Constraint::Reference{table, destination} => {
match self.memory.map.entry(*destination) {
Entry::Occupied(mut o) => {
let table_ref = o.get_mut();
table_ref.set_cell(&Index::Index(1), &Index::Index(1), Value::Reference(*table));
},
Entry::Vacant(v) => {
},
};
},
Constraint::String{table, row, column, value} => {
let table_id = match table {
TableId::Local(id) => *id,
_ => 0,
};
match self.memory.map.entry(table_id) {
Entry::Occupied(mut o) => {
let table_ref = o.get_mut();
table_ref.set_cell(&row, &column, Value::from_string(value.clone()));
},
Entry::Vacant(v) => {
},
};
self.updated = true;
},
Constraint::TableColumn{table, column_ix, column_alias} => {
match self.memory.get_mut(*table) {
Some(table_ref) => {
table_ref.set_column_alias(*column_alias, *column_ix);
}
None => (),
};
},
_ => (),
}
}
if self.errors.len() > 0 {
self.state = BlockState::Error;
}
}
pub fn is_ready(&mut self) -> bool {
if self.state == BlockState::Error || self.state == BlockState::Pending {
false
} else {
let set_diff: HashSet<Register> = self.input_registers.difference(&self.ready).cloned().collect();
if set_diff.len() == 0 {
true
} else {
let mut result = true;
for x in set_diff.iter() {
match x {
Register{table: TableId::Global(y), ..} => {
self.state = BlockState::Unsatisfied;
result = false;
},
_ => (),
}
}
result
}
}
}
pub fn resolve_subscript(&mut self, store: &mut Interner, table: &TableId, indices: &Vec<(Option<Parameter>, Option<Parameter>)>) -> Table {
let mut old: Table = Table::new(0,0,0);
let mut table_id: TableId = table.clone();
'solve_loop: for index in indices {
let mut table_ref = match table_id {
TableId::Local(id) => match self.memory.get(id) {
Some(id) => id,
None => store.get_table(id).unwrap(),
},
TableId::Global(id) => store.get_table(id).unwrap(),
};
let one = vec![Value::from_u64(1)];
let (row_ixes, column_ixes) = match index {
(Some(parameter), None) => {
let ixes: &Vec<Value> = match ¶meter {
Parameter::TableId(TableId::Local(id)) => &self.memory.get(*id).unwrap().data[0],
Parameter::TableId(TableId::Global(id)) => &store.get_table(*id).unwrap().data[0],
Parameter::Index(index) => {
let ix = match table_ref.get_column_index(index) {
Some(ix) => ix,
None => {
break 'solve_loop;
},
};
self.lhs_columns_empty.push(Value::from_u64(ix));
&self.lhs_columns_empty
},
_ => &self.rhs_rows_empty,
};
let (row_ixes, column_ixes) = match (table_ref.rows, table_ref.columns) {
(1, columns) => (&one, ixes),
(rows, 1) => (ixes, &one),
_ => (&self.rhs_rows_empty, ixes),
_ => {
break 'solve_loop;
}
};
(row_ixes, column_ixes)
},
(None, Some(parameter)) => {
let ixes: &Vec<Value> = match ¶meter {
Parameter::TableId(TableId::Local(id)) => &self.memory.get(*id).unwrap().data[0],
Parameter::TableId(TableId::Global(id)) => &store.get_table(*id).unwrap().data[0],
Parameter::Index(index) => {
let ix = match table_ref.get_column_index(index) {
Some(ix) => ix,
None => {
break 'solve_loop;
},
};
self.lhs_columns_empty.push(Value::from_u64(ix));
&self.lhs_columns_empty
},
_ => &self.rhs_rows_empty,
};
(&self.lhs_rows_empty, ixes)
},
(Some(row_parameter), Some(column_parameter)) => {
let row_ixes: &Vec<Value> = match &row_parameter {
Parameter::TableId(TableId::Local(id)) => &self.memory.get(*id).unwrap().data[0],
Parameter::TableId(TableId::Global(id)) => &store.get_table(*id).unwrap().data[0],
_ => &self.rhs_rows_empty,
};
let column_ixes: &Vec<Value> = match &column_parameter {
Parameter::TableId(TableId::Local(id)) => &self.memory.get(*id).unwrap().data[0],
Parameter::TableId(TableId::Global(id)) => &store.get_table(*id).unwrap().data[0],
Parameter::Index(index) => {
let ix = match table_ref.get_column_index(index) {
Some(ix) => ix,
None => {
break 'solve_loop;
},
};
self.lhs_columns_empty.push(Value::from_u64(ix));
&self.lhs_columns_empty
},
_ => &self.lhs_rows_empty,
};
(row_ixes, column_ixes)
},
(Some(parameter), Some(Parameter::All)) => {
let ixes: &Vec<Value> = match ¶meter {
Parameter::TableId(TableId::Local(id)) => &self.memory.get(*id).unwrap().data[0],
Parameter::TableId(TableId::Global(id)) => &store.get_table(*id).unwrap().data[0],
Parameter::Index(index) => {
let ix = match table_ref.get_column_index(index) {
Some(ix) => ix,
None => {
break 'solve_loop;
},
};
self.lhs_columns_empty.push(Value::from_u64(ix));
&self.lhs_columns_empty
},
_ => &self.rhs_rows_empty,
};
(ixes ,&self.rhs_columns_empty)
},
_ => (&self.lhs_rows_empty, &self.rhs_rows_empty),
};
let width = if column_ixes.is_empty() { table_ref.columns }
else { column_ixes.len() as u64 };
let height = if row_ixes.is_empty() { table_ref.rows }
else { row_ixes.len() as u64 };
self.scratch.grow_to_fit(height, width);
let mut iix = 0;
let mut actual_width = 0;
let mut actual_height = 0;
for i in 0..width as usize {
let mut column_mask = true;
let cix = if column_ixes.is_empty() { i }
else {
match column_ixes[i] {
Value::Number(n) => n.to_u64() as usize - 1,
Value::Bool(true) => i,
_ => {
column_mask = false;
0
},
}
};
let mut jix = 0;
for j in 0..height as usize {
let mut row_mask = true;
let rix = if row_ixes.is_empty() { j }
else {
match row_ixes[j] {
Value::Number(n) => n.to_u64() as usize - 1,
Value::Bool(true) => j,
_ => {
row_mask = false;
0
},
}
};
if column_mask == true && row_mask == true {
if cix + 1 > table_ref.columns as usize || rix + 1 > table_ref.rows as usize {
break 'solve_loop;
}
match table_ref.column_index_to_alias.get(cix) {
Some(Some(alias)) => {
self.scratch.column_aliases.insert(*alias, iix as u64 + 1);
if self.scratch.column_index_to_alias.len() < iix + 1 {
self.scratch.column_index_to_alias.resize_with(iix + 1, ||{None});
}
self.scratch.column_index_to_alias[iix] = Some(*alias);
},
_ => (),
};
self.scratch.data[iix][jix] = table_ref.data[cix][rix].clone();
jix += 1;
actual_height = jix;
}
}
if column_mask == true {
iix += 1;
actual_width = iix;
}
}
self.scratch.shrink_to_fit(actual_height as u64, actual_width as u64);
old = self.scratch.clone();
self.scratch.clear();
match &old.index(&Index::Index(1),&Index::Index(1)) {
Some(Value::Reference(id)) => {
match self.current_step {
Some(Constraint::Scan{..}) => {
let register = Register{table: TableId::Global(*id.unwrap()), column: Index::Index(0)};
self.ready.insert(register.clone());
self.input_registers.insert(register.clone());
}
_ => (),
};
table_id = id.clone()
},
_ => (),
};
}
self.rhs_columns_empty.clear();
self.lhs_columns_empty.clear();
let out = old.clone();
self.scratch.clear();
out
}
pub fn solve(&mut self, store: &mut Interner, functions: &HashMap<String, Option<extern "C" fn(Vec<(String, Table)>)->Table>>) {
let block = self as *mut Block;
let mut copy_tables: HashSet<TableId> = HashSet::new();
self.tables_modified.clear();
'solve_loop: for step in &self.plan {
self.current_step = Some(step.clone());
match step {
Constraint::Scan{table, indices, output} => {
let out_table = &output;
let scanned;
unsafe {
scanned = (*block).resolve_subscript(store,table,indices);
}
let out = self.memory.get_mut(*out_table.unwrap()).unwrap();
out.rows = scanned.rows;
out.columns = scanned.columns;
out.data = scanned.data.clone();
out.column_index_to_alias = scanned.column_index_to_alias.clone();
out.column_aliases = scanned.column_aliases.clone();
self.tables_modified.insert(out.id);
self.scratch.clear();
self.rhs_columns_empty.clear();
self.lhs_columns_empty.clear();
},
Constraint::ChangeScan{tables} => {
for (table, indices) in tables {
match (table, indices.as_slice()) {
(TableId::Global(id), [(None, Some(Parameter::Index(index)))]) => {
let register = Register{table: TableId::Global(*id), column: index.clone()};
self.ready.remove(®ister);
}
(TableId::Global(id), _) => {
let register = Register{table:TableId::Global(*id), column: Index::Index(0)};
self.ready.remove(®ister);
}
(TableId::Local(id), _) => {
let table = self.memory.get(*id).unwrap();
if table.data[0][0] == Value::Bool(false) || self.tables_modified.get(id) == None {
self.block_changes.clear();
self.state = BlockState::Unsatisfied;
break 'solve_loop;
}
},
_ => (),
}
}
},
Constraint::Function{fnstring, parameters, output} => {
if *fnstring == "table/split" {
let out_table = &output[0];
let (_, in_table, _) = ¶meters[0];
let table_ref = match in_table {
TableId::Local(id) => self.memory.get(*id).unwrap(),
TableId::Global(id) => store.get_table(*id).unwrap(),
};
self.scratch.grow_to_fit(table_ref.rows, 1);
let cc = table_ref.columns;
let rr = table_ref.rows;
let aliases = table_ref.column_aliases.clone();
let alias_map = table_ref.column_index_to_alias.clone();
let data = table_ref.data.clone();
for i in 0..rr as usize {
let id = Hasher::hash_string(format!("{},table/split-{:?}-row::{},{:?}",i,in_table, i, aliases));
let mut new_table = Table::new(id, 1, cc);
new_table.column_aliases = aliases.clone();
for j in 0..cc as usize {
new_table.data[j][0] = data[j][i].clone();
}
self.memory.insert(new_table);
self.scratch.data[0][i] = Value::Reference(TableId::Local(id));
}
let out = self.memory.get_mut(*out_table.unwrap()).unwrap();
out.rows = self.scratch.rows;
out.columns = self.scratch.columns;
out.data = self.scratch.data.clone();
self.tables_modified.insert(out.id);
self.scratch.clear();
} else {
let out_table = &output[0];
let arguments = parameters.iter().map(|(arg_name, table_id, indices)| {
let table_ref: Table;
unsafe {
table_ref = (*block).resolve_subscript(store,table_id,indices);
}
(arg_name.clone(), table_ref)
}).collect::<Vec<_>>();
let result = match functions.get(fnstring) {
Some(Some(fn_ptr)) => {
fn_ptr(arguments)
}
_ => Table::new(0,1,1),
};
self.scratch = result;
let out = self.memory.get_mut(*out_table.unwrap()).unwrap();
out.rows = self.scratch.rows;
out.columns = self.scratch.columns;
out.data = self.scratch.data.clone();
self.tables_modified.insert(out.id);
self.scratch.clear();
}
},
Constraint::Insert{from, to} => {
let (from_table, from_ixes) = from;
let (to_table, to_ixes) = to;
let to_table_id = match to_table {
TableId::Global(id) => id.clone(),
TableId::Local(id) => 0,
};
let from_table_ref;
unsafe {
from_table_ref = (*block).resolve_subscript(store,from_table,from_ixes);
}
let to_table_ref;
unsafe {
to_table_ref = (*block).resolve_subscript(store,to_table,&vec![(None, None)]);
}
let to_ixes = if to_ixes.len() == 2 {
match (to_ixes[0], to_ixes[1]) {
((None, x),(y,None)) => {
(y,x)
}
_ => to_ixes[0]
}
} else {
to_ixes[0]
};
let one = vec![Value::from_u64(1)];
let (to_row_values, to_column_values) = match to_ixes {
(None, Some(parameter)) |
(Some(parameter), None) => {
let ixes: &Vec<Value> = match ¶meter {
Parameter::TableId(TableId::Local(id)) => &self.memory.get(*id).unwrap().data[0],
Parameter::TableId(TableId::Global(id)) => &store.get_table(*id).unwrap().data[0],
Parameter::Index(index) => {
let ix = match to_table_ref.get_column_index(index) {
Some(ix) => ix,
None => {
break 'solve_loop;
},
};
self.lhs_columns_empty.push(Value::from_u64(ix));
&self.lhs_columns_empty
},
_ => &self.rhs_rows_empty,
};
let (row_ixes, column_ixes) = match (to_table_ref.rows, to_table_ref.columns) {
(1, columns) => (&one, ixes),
(rows, 1) => (ixes, &one),
_ => (&self.rhs_rows_empty, ixes),
_ => {
break 'solve_loop;
}
};
(row_ixes, column_ixes)
},
(Some(row_parameter), Some(column_parameter)) => {
let row_ixes: &Vec<Value> = match &row_parameter {
Parameter::TableId(TableId::Local(id)) => &self.memory.get(*id).unwrap().data[0],
Parameter::TableId(TableId::Global(id)) => &store.get_table(*id).unwrap().data[0],
_ => &self.rhs_rows_empty,
};
let column_ixes: &Vec<Value> = match &column_parameter {
Parameter::TableId(TableId::Local(id)) => &self.memory.get(*id).unwrap().data[0],
Parameter::TableId(TableId::Global(id)) => &store.get_table(*id).unwrap().data[0],
Parameter::Index(index) => {
let ix = match to_table_ref.get_column_index(index) {
Some(ix) => ix,
None => {
break 'solve_loop;
},
};
self.lhs_columns_empty.push(Value::from_u64(ix));
&self.lhs_columns_empty
},
_ => &self.lhs_rows_empty,
};
(row_ixes, column_ixes)
}
_ => (&self.lhs_rows_empty, &self.rhs_rows_empty),
};
let to_width = if to_column_values.is_empty() { to_table_ref.columns }
else { to_column_values.len() as u64 };
let to_height = if to_row_values.is_empty() { to_table_ref.rows }
else { to_row_values.len() as u64 };
let from_height = from_table_ref.rows;
let from_width = from_table_ref.columns;
let to_is_scalar = to_width == 1 && to_height == 1;
let from_is_scalar = from_table_ref.columns == 1 && from_table_ref.rows == 1;
if from_is_scalar {
for i in 0..to_width as usize {
let cix = if to_column_values.is_empty() { i }
else { to_column_values[i].as_u64().unwrap() as usize - 1 };
for j in 0..to_height as usize {
let truth = if to_row_values.is_empty() {
&Value::Bool(true)
} else {
&to_row_values[j]
};
match truth {
Value::Bool(true) => {
let change = Change::Set{table: to_table_id.clone(),
row: Index::Index(j as u64 + 1),
column: Index::Index(cix as u64 + 1),
value: from_table_ref.data[0][0].clone()
};
self.block_changes.push(change);
},
Value::Number(index) => {
let ix = index.mantissa() as usize;
if ix <= to_table_ref.rows as usize {
let change = Change::Set{table: to_table_id.clone(),
row: Index::Index(ix as u64),
column: Index::Index(cix as u64 + 1),
value: from_table_ref.data[0][0].clone()
};
self.block_changes.push(change);
}
}
_ => (),
}
}
}
} else if to_height == from_height && to_width == from_width {
for i in 0..from_width as usize {
let tcix = if to_column_values.is_empty() { i }
else {
match to_column_values[i] {
Value::Number(x) => x.mantissa() as usize - 1,
Value::Bool(true) => i,
_ => {continue; 0},
}
};
for j in 0..from_height as usize {
let trix = if to_row_values.is_empty() { j }
else {
match to_row_values[j] {
Value::Number(x) => x.mantissa() as usize - 1,
Value::Bool(true) => j,
_ => {continue; 0},
}
};
let change = Change::Set{table: to_table_id.clone(),
row: Index::Index(trix as u64 + 1),
column: Index::Index(tcix as u64 + 1),
value: from_table_ref.data[i][j].clone()
};
self.block_changes.push(change);
}
}
}
self.rhs_columns_empty.clear();
self.lhs_columns_empty.clear();
self.rhs_rows_empty.clear();
self.lhs_rows_empty.clear();
},
Constraint::Append{from_table, to_table} => {
let from = match from_table {
TableId::Local(id) => self.memory.get(*id).unwrap(),
TableId::Global(id) => store.get_table(*id).unwrap(),
};
let (to, to_id) = match to_table {
TableId::Local(id) => (self.memory.get(*id).unwrap(), id),
TableId::Global(id) => (store.get_table(*id).unwrap(), id),
};
let from_width = from.columns;
let to_width = to.columns;
if from_width == to_width {
for i in 0..from_width as usize {
for j in 0..from.rows as usize {
self.block_changes.push(Change::Set{table: *to_id, row: Index::Index((j as u64 + to.rows) + 1), column: Index::Index(i as u64 + 1), value: from.data[i][j].clone() });
}
}
}
},
Constraint::CopyTable{from_table, to_table} => {
let mut from_table_ref = self.memory.get(*from_table).unwrap();
let mut changes = vec![Change::NewTable{id: *to_table, rows: from_table_ref.rows, columns: from_table_ref.columns}];
for (alias, ix) in from_table_ref.column_aliases.iter() {
changes.push(Change::RenameColumn{table: *to_table, column_ix: *ix, column_alias: *alias});
}
for (col_ix, column) in from_table_ref.data.iter().enumerate() {
for (row_ix, data) in column.iter().enumerate() {
match data {
Value::Reference(id) => {
copy_tables.insert(*id);
},
_ => (),
}
changes.push(Change::Set{table: *to_table, row: Index::Index(row_ix as u64 + 1), column: Index::Index(col_ix as u64 + 1), value: data.clone()});
}
}
self.block_changes.append(&mut changes);
},
Constraint::NewTable{id, rows, columns} => {
match id {
TableId::Global(id) => {
self.block_changes.push(Change::NewTable{id: *id, rows: *rows, columns: *columns});
}
_ => (),
}
},
_ => (),
}
}
for c in copy_tables.iter() {
self.copy_table(*c, *c, store);
}
if self.errors.len() > 0 {
self.state = BlockState::Error;
} else {
store.process_transaction(&Transaction::from_changeset(self.block_changes.clone()));
self.updated = true;
}
self.block_changes.clear();
self.state = BlockState::Updated;
self.current_step = None;
}
fn copy_table(&mut self, from_table: TableId, to_table: TableId, store: &Interner) {
let mut copy_tables: HashSet<TableId> = HashSet::new();
let mut from_table_ref = match from_table {
TableId::Local(id) => {
match self.memory.get(id) {
None => store.get_table(id).unwrap(),
Some(table) => table,
}
},
TableId::Global(id) => store.get_table(id).unwrap(),
};
let to_table_id = match to_table {
TableId::Local(id) => id,
TableId::Global(id) => id,
};
let mut changes = vec![Change::NewTable{id: to_table_id, rows: from_table_ref.rows, columns: from_table_ref.columns}];
for (alias, ix) in from_table_ref.column_aliases.iter() {
changes.push(Change::RenameColumn{table: to_table_id, column_ix: *ix, column_alias: *alias});
}
for (col_ix, column) in from_table_ref.data.iter().enumerate() {
for (row_ix, data) in column.iter().enumerate() {
match data {
Value::Reference(id) => {
copy_tables.insert(*id);
},
_ => (),
}
changes.push(Change::Set{table: to_table_id, row: Index::Index(row_ix as u64 + 1), column: Index::Index(col_ix as u64 + 1), value: data.clone()});
}
}
for c in copy_tables.iter() {
self.copy_table(*c, *c, store);
}
self.block_changes.append(&mut changes);
}
}
impl fmt::Debug for Block {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "┌────────────────────────────────────────┐\n").unwrap();
write!(f, "│ Block {:?} ({:#x})\n", self.name, self.id).unwrap();
write!(f, "├────────────────────────────────────────┤\n").unwrap();
write!(f, "│ \n{}\n",self.text).unwrap();
write!(f, "├────────────────────────────────────────┤\n").unwrap();
write!(f, "│ Errors:\n").unwrap();
write!(f, "│ {:?}\n", self.errors).unwrap();
write!(f, "├────────────────────────────────────────┤\n").unwrap();
write!(f, "│ State: {:?}\n", self.state).unwrap();
write!(f, "│ Ready: {:?}\n", self.ready).unwrap();
write!(f, "│ Updated: {:?}\n", self.updated).unwrap();
write!(f, "│ Input: {:?}\n", self.input_registers.len()).unwrap();
for (ix, register) in self.input_registers.iter().enumerate() {
write!(f, "│ {:?}. {:?}\n", ix + 1, register).unwrap();
}
write!(f, "│ Output: {:?}\n", self.output_registers.len()).unwrap();
for (ix, register) in self.output_registers.iter().enumerate() {
write!(f, "│ {:?}. {:?}\n", ix + 1, register).unwrap();
}
write!(f, "│ Constraints: {:?}\n", self.constraints.len()).unwrap();
for (ix, (text, constraint)) in self.constraints.iter().enumerate() {
write!(f, "│ {}. {}\n", ix + 1, text).unwrap();
for constraint_step in constraint {
write!(f, "│ > {:?}\n", constraint_step).unwrap();
}
}
write!(f, "│ Plan: {:?}\n", self.plan.len()).unwrap();
for (ix, step) in self.plan.iter().enumerate() {
write!(f, "│ {:?}. {:?}\n", ix + 1, step).unwrap();
}
write!(f, "└────────────────────────────────────────┘\n").unwrap();
write!(f, "{:?}\n", self.memory).unwrap();
Ok(())
}
}
#[derive(Clone, PartialEq)]
pub enum Constraint {
NewTable{id: TableId, rows: u64, columns: u64},
TableColumn{table: u64, column_ix: u64, column_alias: u64},
Reference{table: TableId, destination: u64},
Scan {table: TableId, indices: Vec<(Option<Parameter>, Option<Parameter>)>, output: TableId},
ChangeScan {tables: Vec<(TableId, Vec<(Option<Parameter>, Option<Parameter>)>)>},
Identifier {id: u64, text: String},
Function {fnstring: String, parameters: Vec<(String, TableId, Vec<(Option<Parameter>, Option<Parameter>)>)>, output: Vec<TableId>},
Constant {table: TableId, row: Index, column: Index, value: Quantity, unit: Option<String>},
String {table: TableId, row: Index, column: Index, value: String},
CopyTable {from_table: u64, to_table: u64},
AliasTable {table: TableId, alias: u64},
Insert {from: (TableId, Vec<(Option<Parameter>,Option<Parameter>)>), to: (TableId, Vec<(Option<Parameter>,Option<Parameter>)>)},
Append {from_table: TableId, to_table: TableId},
Empty{table: TableId, row: Index, column: Index},
Null,
}
impl fmt::Debug for Constraint {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Constraint::Reference{table, destination} => write!(f, "Reference({:?} -> {:#x})", table, destination),
Constraint::NewTable{id, rows, columns} => write!(f, "NewTable(#{:?}({:?}x{:?}))", id, rows, columns),
Constraint::Scan{table, indices, output} => write!(f, "Scan(#{:?}({:?}) -> {:?})", table, indices, output),
Constraint::ChangeScan{tables} => write!(f, "ChangeScan({:?})", tables),
Constraint::Function{fnstring, parameters, output} => write!(f, "Function({:?}({:?}) -> {:?})", fnstring, parameters, output),
Constraint::Constant{table, row, column, value, unit} => write!(f, "Constant({}{:?} -> #{:?})", value.to_float(), unit, table),
Constraint::String{table, row, column, value} => write!(f, "String({:?} -> #{:?})", value, table),
Constraint::CopyTable{from_table, to_table} => write!(f, "CopyTable({:#x} -> {:#x})", from_table, to_table),
Constraint::AliasTable{table, alias} => write!(f, "AliasTable({:?} -> {:#x})", table, alias),
Constraint::Identifier{id, text} => write!(f, "Identifier(\"{}\" = {:#x})", text, id),
Constraint::Insert{from, to} => write!(f, "Insert({:?} -> {:?})", from, to),
Constraint::Append{from_table, to_table} => write!(f, "Append({:?} -> {:?})", from_table, to_table),
Constraint::TableColumn{table, column_ix, column_alias} => write!(f, "TableColumn(#{:#x}({:#x}) -> {:#x})", table, column_ix, column_alias),
Constraint::Empty{table, row, column} => write!(f, "Empty -> #{:?} {:?} {:?}", table, row, column),
Constraint::Null => write!(f, "Null"),
}
}
}
pub fn check_bits(solved: u64, checking: u64) -> bool {
solved & checking == checking
}
pub fn has_any_bits(solved: u64, checking: u64) -> bool {
solved & checking != 0
}
pub fn set_bit(solved: u64, bit: usize) -> u64 {
solved | (1 << bit)
}
pub fn clear_bit(solved: u64, bit: usize) -> u64 {
solved & !(1 << bit)
}
pub fn check_bit(solved: u64, bit: usize) -> bool {
solved & (1 << bit) != 0
}