diff --git a/.gitignore b/.gitignore
index ea8c4bf..4f96631 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
/target
+/dist
diff --git a/Cargo.lock b/Cargo.lock
index e1e220c..d07c290 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,5 +1,43 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
+[[package]]
+name = "bumpalo"
+version = "3.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
+dependencies = [
+ "cfg-if 0.1.10",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "console_log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494"
+dependencies = [
+ "log",
+ "web-sys",
+]
+
[[package]]
name = "either"
version = "1.6.1"
@@ -15,14 +53,142 @@ dependencies = [
"either",
]
+[[package]]
+name = "js-sys"
+version = "0.3.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78"
+dependencies = [
+ "wasm-bindgen",
+]
+
[[package]]
name = "kv"
version = "0.0.1"
dependencies = [
+ "console_error_panic_hook",
+ "console_log",
"itertools",
+ "log",
"svg_fmt",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "log"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
]
[[package]]
name = "svg_fmt"
version = "0.4.0"
+
+[[package]]
+name = "syn"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7"
+dependencies = [
+ "cfg-if 1.0.0",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8"
+dependencies = [
+ "bumpalo",
+ "lazy_static",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1"
+
+[[package]]
+name = "web-sys"
+version = "0.3.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
diff --git a/Cargo.toml b/Cargo.toml
index d05514c..f0abb5b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,5 +7,10 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+console_error_panic_hook = "0.1.6"
+console_log = "0.2.0"
itertools = "0.10.0"
+log = "0.4.14"
svg_fmt = { path = "../rust_debug/svg_fmt" }
+wasm-bindgen = "0.2.71"
+web-sys = { version = "0.3.48", features = ["Window", "Document", "Location", "HtmlCollection", "HtmlElement", "CssStyleDeclaration", "HtmlTextAreaElement", "HtmlInputElement"] }
diff --git a/base.js b/base.js
new file mode 100644
index 0000000..765b687
--- /dev/null
+++ b/base.js
@@ -0,0 +1,23 @@
+function handleTextChange(event) {
+ const target = event.target;
+ const value = target.value;
+ if (value.length == 0) {
+ target.value = "-";
+ } else {
+ target.value = value.substr(value.length - 1);
+ }
+}
+function handleTextScroll(event) {
+ const target = event.target;
+ const value = target.value;
+ if (event.deltaY < 0) {
+ target.value = "1"; // scroll up
+ } else {
+ target.value = "0"; // scroll down
+ }
+ event.preventDefault();
+}
+export function attachTypeListener(element) {
+ element.addEventListener("input", handleTextChange);
+ element.addEventListener("wheel", handleTextScroll);
+}
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..9620139
--- /dev/null
+++ b/index.html
@@ -0,0 +1,49 @@
+
+
+
+
+ KV diagram calculator
+
+
+
+
+
+
+
+
+
+ Change cells by scrolling (up => 1, down => 0), typing (=> 1, 0) or deleting (=> -).
+
+
+ Load example 1, example 2, example 3.
+
+
+
+
+
+
+
+
diff --git a/src/bin/svg-wasm.rs b/src/bin/svg-wasm.rs
new file mode 100644
index 0000000..f1e06f4
--- /dev/null
+++ b/src/bin/svg-wasm.rs
@@ -0,0 +1,243 @@
+use wasm_bindgen::prelude::*;
+use wasm_bindgen::JsCast;
+use log::{Level, info};
+
+use kv::*;
+use web_sys::{EventTarget, HtmlElement, HtmlInputElement, HtmlTextAreaElement};
+
+macro_rules! web {
+ ($($x:ident)*) => {
+ web_sys::window().unwrap()$(.$x().unwrap())*
+ }
+}
+
+macro_rules! web2 {
+ ($($x:ident)*) => {
+ web_sys::window().unwrap()$(.$x())*
+ }
+}
+
+const HINT_TEXT: &'static str = "Output: core blocks, prime blocks, solution 1, solution 2, ... (solutions only displayed if not equal to core or prime blocks)";
+
+fn main() {
+ console_log::init_with_level(Level::Debug).unwrap();
+ std::panic::set_hook(Box::new(console_error_panic_hook::hook));
+ info!("init");
+ init_settings();
+ if !parse_hash() {
+ let grid = grid(get_var_number());
+ update_input_grid(&grid);
+ }
+ let closure = Closure::wrap(Box::new(|| { parse_hash(); }) as Box);
+ web!().add_event_listener_with_callback("hashchange", closure.as_ref().unchecked_ref()).unwrap();
+ closure.forget();
+}
+
+fn parse_hash() -> bool {
+ let hash = web!(document location hash);
+ if hash.len() >= 2 {
+ let func_spec = &hash[1..];
+ let var_count = (func_spec.len() as f32).log2() as usize;
+ if 2usize.pow(var_count as u32) == func_spec.len() {
+ set_var_number(var_count);
+ let grid = grid(var_count);
+ update_input_grid(&grid);
+ set_input_function(func_spec);
+ return true;
+ }
+ }
+ false
+}
+
+#[wasm_bindgen(module = "/base.js")]
+extern "C" {
+ pub fn attachTypeListener(element: &HtmlElement);
+}
+
+fn get_output_container() -> HtmlElement {
+ web!(document).get_element_by_id("output-container").unwrap().unchecked_into::()
+}
+
+fn get_output_help() -> HtmlElement {
+ web!(document).get_element_by_id("output-help").unwrap().unchecked_into::()
+}
+
+fn p(text: &str) -> HtmlElement {
+ let p = web!(document).create_element("p").unwrap().unchecked_into::();
+ p.set_inner_text(text);
+ p
+}
+
+fn span(text: &str) -> HtmlElement {
+ let p = web!(document).create_element("span").unwrap().unchecked_into::();
+ p.set_inner_text(text);
+ p
+}
+
+pub fn run() {
+ let document = web!(document);
+
+ let var_count = get_var_number();
+ let vars = (0..var_count).map(|x| 2usize.pow(x as u32)).collect::>();
+ let function: FunctionSpec = (0..2usize.pow(var_count as u32)).map(|idx| get_input(idx)).collect();
+ info!("function: {:?}", function);
+ let hash = Some('#').into_iter().chain(function.iter().map::(|&x| x.into())).collect::();
+ web2!(location).set_hash(&hash).unwrap();
+ let groups = find_groups(&function, &vars, One);
+ let (prime, other) = find_core(&function, &vars, One, &groups);
+ let solutions = real_solutions_idxed(function.clone(), &vars, One, &prime, &other);
+
+ let output_container = get_output_container();
+ if output_container.children().length() == 0 {
+ let output_help = get_output_help();
+ output_help.append_child(&p(HINT_TEXT)).unwrap();
+ output_container.append_child(&document.create_element("hr").unwrap()).unwrap();
+ }
+ let output_sub = document.create_element("div").unwrap().unchecked_into::();
+
+ let (_grid, w, h) = grid(var_count);
+
+ macro_rules! render_svg {
+ ($sol:expr, $mask:expr) => {
+ let svg = svg::get_svg(if var_count < 5 { 64 } else { 80 }, &function, &vars, $mask);
+ let svg_container = document.create_element("div").unwrap();
+ svg_container.set_class_name("solution");
+ svg_container.set_inner_html(&svg);
+ let svg = svg_container.children().item(0).unwrap().unchecked_into::();
+ svg.style().set_property("width", &format!("{}px", w * 80)).unwrap();
+ svg.style().set_property("height", &format!("{}px", h * 80)).unwrap();
+ let mut text = String::new();
+ for x in $sol {
+ if !text.is_empty() {
+ text += " ∨ ";
+ }
+ text += &print_implicant(x);
+ }
+ if text.is_empty() {
+ text += ".";
+ }
+ svg_container.append_child(&span(&text)).unwrap();
+ output_sub.append_child(&svg_container).unwrap();
+ };
+ }
+
+ let mut block_masks: Vec<_> = prime.iter()
+ .map(block_to_mask)
+ .collect();
+ render_svg!(&prime, &block_masks);
+
+ block_masks = prime.iter()
+ .map(block_to_mask)
+ .chain(other.iter().map(block_to_mask)) // also display non-core
+ .collect();
+ render_svg!(prime.iter().chain(other.iter()), &block_masks);
+
+ let mut size = usize::MAX;
+ for sol in &solutions {
+ if sol.len() > size {
+ break;
+ }
+ size = sol.len();
+ block_masks = prime.iter()
+ .map(block_to_mask)
+ .chain((0..other.len()).map(|idx| {
+ if sol.contains(&idx) {
+ block_to_mask(&other[idx])
+ } else {
+ (!0, 0)
+ }
+ }))
+ .collect();
+ let blocks = prime.iter()
+ .chain(sol.iter().map(|&i| &other[i]));
+ render_svg!(blocks, &block_masks);
+ }
+
+ output_container.prepend_with_node_1(&output_sub).unwrap();
+ output_container.prepend_with_node_1(&document.create_element("hr").unwrap()).unwrap();
+}
+
+fn set_var_number(x: usize) {
+ get_var_number_el().set_value(&x.to_string());
+}
+
+fn init_settings() {
+ let calculate = web!(document).get_element_by_id("calculate").unwrap().unchecked_into::();
+ let closure = Closure::wrap(Box::new(|| run()) as Box);
+ calculate.add_event_listener_with_callback("click", closure.as_ref().unchecked_ref()).unwrap();
+ closure.forget();
+ let apply_count = web!(document).get_element_by_id("apply-variables").unwrap().unchecked_into::();
+ let closure = Closure::wrap(Box::new(|| update_input_grid(&grid(get_var_number()))) as Box);
+ apply_count.add_event_listener_with_callback("click", closure.as_ref().unchecked_ref()).unwrap();
+ closure.forget();
+}
+
+fn get_var_number_el() -> HtmlInputElement {
+ web!(document).get_element_by_id("variables").unwrap().unchecked_into()
+}
+
+fn get_var_number() -> usize {
+ get_var_number_el().value().parse().unwrap()
+}
+
+fn get_input_container() -> HtmlElement {
+ web!(document).get_element_by_id("input-container").unwrap().unchecked_into::()
+}
+
+fn get_input_el(idx: usize) -> Option {
+ web!(document).get_element_by_id(&format!("input{}", idx)).map(|x| x.unchecked_into::())
+}
+
+fn create_input_el(idx: usize, x: usize, y: usize) -> HtmlElement {
+ let input = web!(document).create_element("textarea").unwrap().unchecked_into::();
+ input.set_attribute("id", &format!("input{}", idx)).unwrap();
+ input.set_value("-");
+ let style = input.style();
+ style.set_property("position", "absolute").unwrap();
+ style.set_property("left", &format!("{}px", x)).unwrap();
+ style.set_property("top", &format!("{}px", y)).unwrap();
+ get_input_container().append_child(&input).unwrap();
+ attachTypeListener(&input);
+ input.into()
+}
+
+fn get_input(idx: usize) -> Output {
+ let el = get_input_el(idx).unwrap().unchecked_into::();
+ match &*el.value() {
+ "0" => Zero,
+ "1" => One,
+ _ => Any
+ }
+}
+
+fn set_input(idx: usize, out: Output) {
+ let el = get_input_el(idx).unwrap().unchecked_into::();
+ el.set_value(&out.to_string());
+}
+
+fn set_input_function(func: &str) {
+ for i in 0..func.len() {
+ set_input(i, func[i..i+1].parse().unwrap());
+ }
+}
+
+// also set in style
+const GRID_SPACING: usize = 64;
+
+fn update_input_grid((grid, w, h): &(Vec<(usize, usize)>, usize, usize)) {
+ let input_container = get_input_container();
+ input_container.style().set_property("width", &format!("{}px", w * 64)).unwrap();
+ input_container.style().set_property("height", &format!("{}px", h * 64)).unwrap();
+ for i in 0..grid.len() {
+ if get_input_el(i).is_none() {
+ create_input_el(i, grid[i].0 * GRID_SPACING, grid[i].1 * GRID_SPACING);
+ }
+ }
+ for i in grid.len().. {
+ if let Some(el) = get_input_el(i) {
+ el.remove();
+ } else {
+ break;
+ }
+ }
+}
diff --git a/src/bin/svg.rs b/src/bin/svg.rs
index acfc166..c894876 100644
--- a/src/bin/svg.rs
+++ b/src/bin/svg.rs
@@ -1,32 +1,23 @@
use std::env::args;
-use svg_fmt::*;
-
use kv::*;
const SIZE_FACTOR: usize = 64;
-const SIZE_FONT: f32 = 20.0;
-const SIZE4: usize = SIZE_FACTOR / 4;
-
-const COLORS: &'static [Color] = &[
- rgb(0, 0, 255),
- rgb(255, 0, 0),
- rgb(0, 255, 0),
- rgb(255, 255, 0),
-];
fn main() {
let args = args().collect::>();
- let vars = [A, B, C];
- let function = vec![0, 0, 1, 1, 1, 1, 1, 0].into_iter().map(Into::into).collect();
+ let vars = [A, B, C, D];
+ //let function = vec![0, 0, 1, 1, 1, 1, 1, 0].into_iter().map(Into::into).collect();
+ //let function = vec![0, 0, 1, 1, 1, 1, 1, 2].into_iter().map(Into::into).collect();
+ let function = parse_function("-1111000-1-01---");
let groups = find_groups(&function, &vars, One);
eprintln!("all:");
for x in &groups {
eprintln!("{}", print_implicant(x));
}
eprintln!("prime:");
- let (prime, other) = find_prime(&function, &vars, One, &groups);
+ let (prime, other) = find_core(&function, &vars, One, &groups);
for x in &prime {
eprintln!("{}", print_implicant(x));
}
@@ -54,93 +45,5 @@ fn main() {
.collect()
};
- let (grid, w, h) = grid(3);
- println!("{}", BeginSvg { w: w * SIZE_FACTOR + 3, h: h * SIZE_FACTOR + 3 });
- for (i, &(x, y)) in grid.iter().enumerate() {
- println!("{}",
- rectangle(1 + x * SIZE_FACTOR, 1 + y * SIZE_FACTOR, SIZE_FACTOR, SIZE_FACTOR)
- .fill(white())
- .stroke(Stroke::Color(black(), 2.0))
- );
- let mut rect = rectangle(1 + x * SIZE_FACTOR, 1 + y * SIZE_FACTOR, SIZE_FACTOR, SIZE_FACTOR)
- .fill(white())
- .stroke_opacity(0.7)
- .inflate(-1, -1);
- let mut ident = 1;
- for (idx, &(mask, inv_mask)) in block_masks.iter().enumerate() {
- rect = rect.inflate(-2, -2);
- ident += 2;
- if check_mask(i, mask, inv_mask) {
- // check cells around this one
- let mut up = false;
- let mut down = false;
- let mut left = false;
- let mut right = false;
- for &var in &vars {
- let j = i ^ var;
- if check_mask(j, mask, inv_mask) {
- let (x2, y2) = grid[j];
- if (x + 1) % w == x2 && y == y2 {
- right = true;
- }
- if x == x2 && (y + 1) % h == y2 {
- down = true;
- }
- if x == x2 && y == (y2 + 1) % h {
- up = true;
- }
- if x == (x2 + 1) % w && y == y2 {
- left = true;
- }
- if !up && !down && !left && !right {
- unreachable!()
- }
- }
- }
- let mut sides = rect.sides();
- for s in &mut sides {
- *s = s.opacity(0.9);
- }
- if up {
- println!("{}", sides[0].width(2.0).color(white()));
- println!("{}", sides[2].width(2.0).color(COLORS[idx]).offset(0.0, -ident - 1));
- println!("{}", sides[3].width(2.0).color(COLORS[idx]).offset(0.0, -ident - 1));
- } else {
- println!("{}", sides[0].width(2.0).color(COLORS[idx]));
- }
- if down {
- println!("{}", sides[1].width(2.0).color(white()));
- println!("{}", sides[2].width(2.0).color(COLORS[idx]).offset(0.0, ident + 1));
- println!("{}", sides[3].width(2.0).color(COLORS[idx]).offset(0.0, ident + 1));
- } else {
- println!("{}", sides[1].width(2.0).color(COLORS[idx]));
- }
- if left {
- println!("{}", sides[2].width(2.0).color(white()));
- println!("{}", sides[0].width(2.0).color(COLORS[idx]).offset(-ident - 1, 0));
- println!("{}", sides[1].width(2.0).color(COLORS[idx]).offset(-ident - 1, 0));
- } else {
- println!("{}", sides[2].width(2.0).color(COLORS[idx]));
- }
- if right {
- println!("{}", sides[3].width(1.0).color(white()));
- println!("{}", sides[0].width(2.0).color(COLORS[idx]).offset(ident + 1, 0));
- println!("{}", sides[1].width(2.0).color(COLORS[idx]).offset(ident + 1, 0));
- } else {
- println!("{}", sides[3].width(2.0).color(COLORS[idx]));
- }
- }
- }
- println!("{}",
- text((x+1) * SIZE_FACTOR - SIZE4, (y+1) * SIZE_FACTOR - SIZE4 / 3, i.to_string())
- .size(SIZE_FONT)
- .color(black())
- );
- println!("{}",
- text(x * SIZE_FACTOR + SIZE4, (y+1) * SIZE_FACTOR - SIZE4, function[i].to_string())
- .size(SIZE_FONT * 2.0)
- .color(black())
- );
- }
- println!("{}", EndSvg);
+ println!("{}", svg::get_svg(SIZE_FACTOR, &function, &vars, &block_masks));
}
diff --git a/src/lib.rs b/src/lib.rs
index ed50770..700b174 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,8 +1,9 @@
-use std::fmt;
+use std::{fmt, str::FromStr};
use itertools::Itertools;
mod ui;
+use log::{debug, trace, warn};
pub use ui::*;
pub type Variable = usize;
@@ -12,6 +13,8 @@ pub type BlockRef<'a> = &'a [(Variable, Output)];
pub const A: Variable = 1 << 0;
pub const B: Variable = 1 << 1;
pub const C: Variable = 1 << 2;
+pub const D: Variable = 1 << 3;
+pub const E: Variable = 1 << 4;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Output {
@@ -25,45 +28,86 @@ pub use Output::*;
impl Output {
fn to_num(self) -> usize {
match self {
- Zero => 0,
- One => 1,
- Any => todo!()
+ Zero => 0,
+ One => 1,
+ Any => todo!()
}
}
fn invert(self) -> Self {
match self {
- Zero => One,
- One => Zero,
- Any => Any
+ Zero => One,
+ One => Zero,
+ Any => Any
}
}
}
impl From for Output {
- fn from(x: usize) -> Self {
- match x {
+ fn from(x: usize) -> Self {
+ match x {
0 => Zero,
1 => One,
- _ => todo!()
+ _ => Any
}
- }
+ }
+}
+
+impl From for Output {
+ fn from(x: char) -> Self {
+ match x {
+ '0' => Zero,
+ '1' => One,
+ _ => Any
+ }
+ }
+}
+
+impl FromStr for Output {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result {
+ Ok(match s {
+ "0" => Zero,
+ "1" => One,
+ _ => Any
+ })
+ }
}
impl fmt::Display for Output {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Zero => write!(f, "0"),
- One => write!(f, "1"),
- Any => write!(f, "-")
- }
- }
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Zero => write!(f, "0"),
+ One => write!(f, "1"),
+ Any => write!(f, "-")
+ }
+ }
+}
+
+impl Into for Output {
+ fn into(self) -> char {
+ match self {
+ Zero => '0',
+ One => '1',
+ Any => '-'
+ }
+ }
+}
+
+pub fn parse_function(func: &str) -> FunctionSpec {
+ func.chars().map(|x| x.into()).collect()
}
pub type FunctionSpec = Vec