lib.rs
26.0 kB · rust · 692 lines
1#![allow(non_camel_case_types, non_snake_case, clippy::too_many_arguments)]23mod hand;45use wasm_bindgen::prelude::*;67/// Returns whether a rule is affine, its algebraic degree at most one.8#[wasm_bindgen]9pub fn affine(rule: u8) -> Result<bool, JsValue> {10 let value = mrlyrs::life::affine(rule);11 Ok(value)12}1314/// Runs a seed under a config until it fixes, loops or times out, recording every generation.15#[wasm_bindgen]16pub fn animate(seed: JsValue, config: &Config) -> Result<Life, JsValue> {17 let seed = hand::cell2d_from_js(&seed)?;18 let value = mrlyrs::life::animate(&seed, &config.inner).map_err(hand::throw)?;19 Ok(Life { inner: value })20}2122/// Returns the mean fraction of sites changed between consecutive grids.23#[wasm_bindgen]24pub fn churn(grids: JsValue) -> Result<f64, JsValue> {25 let grids = hand::list_from_js(&grids, hand::cell2d_from_js)?;26 let value = mrlyrs::life::churn(&grids);27 Ok(value)28}2930/// Returns the eight output bits of a rule, corner `i` at index `i = 4 x0 + 2 x1 + x2`.31#[wasm_bindgen]32pub fn corner_bits(rule: u8) -> Result<Vec<u8>, JsValue> {33 let value = mrlyrs::life::corner_bits(rule);34 Ok(value)35}3637/// Returns the sequence up to max_neighbors, keeping zeros and ones only on request.38#[wasm_bindgen]39pub fn counts(seq: &Source, max_neighbors: usize, include_zeros: bool, include_ones: bool) -> Result<Vec<usize>, JsValue> {40 let value = mrlyrs::life::counts(seq.inner, max_neighbors, include_zeros, include_ones).map_err(hand::throw)?;41 Ok(value)42}4344/// Crops a frame sequence to the centred square bounding every cell ever alive.45#[wasm_bindgen]46pub fn crop(grids: JsValue) -> Result<JsValue, JsValue> {47 let grids = hand::list_from_js(&grids, hand::cell2d_from_js)?;48 let value = mrlyrs::life::crop(&grids).map_err(hand::throw)?;49 hand::list_to_js(&value, hand::cell2d_to_js)50}5152/// Returns the rules a rule reaches under the signed axis permutations of the cube, in ascending order.53#[wasm_bindgen]54pub fn cube_orbit(rule: u8) -> Result<Vec<u8>, JsValue> {55 let value = mrlyrs::life::cube_orbit(rule);56 Ok(value)57}5859/// Builds the base-2 design mask a code names at an odd side grown to the given Kronecker60#[wasm_bindgen]61pub fn design_mask(dimension: usize, code: JsValue, number: usize, level: usize) -> Result<JsValue, JsValue> {62 let code = hand::code_from_js(&code)?;63 let value = mrlyrs::life::design_mask(dimension, code, number, level).map_err(hand::throw)?;64 hand::tensor_to_js(&value)65}6667/// Returns the bit a rule sends the neighbourhood to, reading bit `4l + 2c + r` in Wolfram's numbering off the low bit of each cell.68#[wasm_bindgen]69pub fn elementary_output(rule: u8, l: u8, c: u8, r: u8) -> Result<u8, JsValue> {70 let value = mrlyrs::life::elementary::output(rule, l, c, r);71 Ok(value)72}7374/// Returns the grid's binary Shannon entropy in millibits.75#[wasm_bindgen]76pub fn entropy(grid: JsValue) -> Result<i64, JsValue> {77 let grid = hand::cell2d_from_js(&grid)?;78 let value = mrlyrs::life::entropy(&grid);79 Ok(value)80}8182/// Renders grids to white-on-black PNG bytes at a pixel scale.83#[wasm_bindgen]84pub fn frames(grids: JsValue, scale: usize) -> Result<JsValue, JsValue> {85 let grids = hand::list_from_js(&grids, hand::cell2d_from_js)?;86 let value = mrlyrs::life::frames(&grids, scale).map_err(hand::throw)?;87 hand::list_to_js(&value, |x1| Ok(hand::typed(&(*x1)[..])))88}8990/// Returns the base-2 plane design a rule's single seed draws, or None when it draws none.91#[wasm_bindgen]92pub fn gasket(rule: u8) -> Result<JsValue, JsValue> {93 let value = mrlyrs::life::gasket(rule);94 hand::to_js(&value)95}9697/// Returns the genus of a rule's cube class: `iso` when it meets a level set, `axis` when it meets an axis-pinned block, else `comp`.98#[wasm_bindgen]99pub fn genus(rule: u8) -> Result<String, JsValue> {100 let value = mrlyrs::life::genus(rule);101 Ok(value)102}103104/// Renders a whole run's cumulative-visit heatmap frames with the heat ramp.105#[wasm_bindgen]106pub fn heatmap(grids: JsValue, scale: usize) -> Result<JsValue, JsValue> {107 let grids = hand::list_from_js(&grids, hand::cell2d_from_js)?;108 let value = mrlyrs::life::heatmap(&grids, scale).map_err(hand::throw)?;109 hand::list_to_js(&value, |x1| Ok(hand::typed(&(*x1)[..])))110}111112/// Returns the space-time diagram of a seed row, row 0 the seed and then one row per generation.113#[wasm_bindgen]114pub fn history(row: &[u8], rule: u8, steps: usize, wrap: bool) -> Result<JsValue, JsValue> {115 let value = mrlyrs::life::history(row, rule, steps, wrap).map_err(hand::throw)?;116 hand::tensor_to_js(&value)117}118119/// Returns Langton's lambda, the popcount over eight.120#[wasm_bindgen]121pub fn lambda(rule: u8) -> Result<f64, JsValue> {122 let value = mrlyrs::life::lambda(rule);123 Ok(value)124}125126/// Returns the index of the lattice the mask offsets generate together with the centre, zero when they do not span the dimension.127#[wasm_bindgen]128pub fn lattice_index(mask: JsValue) -> Result<usize, JsValue> {129 let mask = hand::tensor_from_js(&mask)?;130 let value = mrlyrs::life::lattice_index(&mask);131 Ok(value)132}133134/// Returns the offsets a mask's filled sites take from its centre, the centre itself dropped.135#[wasm_bindgen]136pub fn mask_offsets(mask: JsValue) -> Result<JsValue, JsValue> {137 let mask = hand::tensor_from_js(&mask)?;138 let value = mrlyrs::life::mask_offsets(&mask);139 hand::list_to_js(&value, |x1| Ok(hand::typed(&(*x1)[..])))140}141142/// Builds the 3 by 3 Moore mask, every site on but the center.143#[wasm_bindgen]144pub fn moore() -> Result<JsValue, JsValue> {145 let value = mrlyrs::life::moore().map_err(hand::throw)?;146 hand::cell2d_to_js(&value)147}148149/// Renders grids into one looping black-on-white gif, the delay in hundredths of a second.150#[wasm_bindgen]151pub fn movie(grids: JsValue, scale: usize, delay: usize) -> Result<Vec<u8>, JsValue> {152 let grids = hand::list_from_js(&grids, hand::cell2d_from_js)?;153 let value = mrlyrs::life::movie(&grids, scale, delay).map_err(hand::throw)?;154 Ok(value)155}156157/// Advances a grid one generation under birth and survive counts, a neighbor mask and a boundary.158#[wasm_bindgen]159pub fn next_grid(cell: JsValue, birth: &[usize], survive: &[usize], mask: JsValue, boundary: JsValue) -> Result<JsValue, JsValue> {160 let cell = hand::cell2d_from_js(&cell)?;161 let mask = hand::tensor_from_js(&mask)?;162 let boundary = hand::from_js::<mrlyrs::life::Boundary>(&boundary)?;163 let value = mrlyrs::life::next_grid(&cell, birth, survive, &mask, boundary).map_err(hand::throw)?;164 hand::cell2d_to_js(&value)165}166167/// Returns the rules a rule reaches under the cube group together with the output complement, its NPN class, in ascending order.168#[wasm_bindgen]169pub fn npn_class(rule: u8) -> Result<Vec<u8>, JsValue> {170 let value = mrlyrs::life::npn_class(rule);171 Ok(value)172}173174/// Returns the birth and survive counts of a rule read outer-totalistically on its two outer cells, or None when it does not read them by count alone.175#[wasm_bindgen]176pub fn outer_totalistic(rule: u8) -> Result<JsValue, JsValue> {177 let value = mrlyrs::life::outer_totalistic(rule);178 hand::option_to_js(value.as_ref(), |x1| Ok(hand::tuple_to_js(&[hand::typed(&(x1.0)[..]), hand::typed(&(x1.1)[..])])))179}180181/// Returns the count of neighbourhoods a rule sends to one.182#[wasm_bindgen]183pub fn popcount(rule: u8) -> Result<u32, JsValue> {184 let value = mrlyrs::life::popcount(rule);185 Ok(value)186}187188/// Renders one grid to white-on-black PNG bytes at a pixel scale.189#[wasm_bindgen]190pub fn render_frame(grid: JsValue, scale: usize) -> Result<Vec<u8>, JsValue> {191 let grid = hand::cell2d_from_js(&grid)?;192 let value = mrlyrs::life::render::frame(&grid, scale).map_err(hand::throw)?;193 Ok(value)194}195196/// Returns whether a rule is reversible, by the pair graph on the de Bruijn nodes pruned to its bi-infinite core.197#[wasm_bindgen]198pub fn reversible(rule: u8) -> Result<bool, JsValue> {199 let value = mrlyrs::life::reversible(rule);200 Ok(value)201}202203/// Returns the GF(2) algebraic degree of a rule, minus one for the zero rule.204#[wasm_bindgen]205pub fn rule_degree(rule: u8) -> Result<i32, JsValue> {206 let value = mrlyrs::life::rule_degree(rule);207 Ok(value)208}209210/// Returns the design name a rule carries, `bang dim 3, code <rule>`.211#[wasm_bindgen]212pub fn rule_name(rule: u8) -> Result<String, JsValue> {213 let value = mrlyrs::life::rule_name(rule).map_err(hand::throw)?;214 Ok(value)215}216217/// Returns the single-seed diagram: one live cell run the given generations on a line padded by `steps` cells beyond the `2 steps + 1` window on each side, cropped back to that window.218#[wasm_bindgen]219pub fn single_seed(rule: u8, steps: usize) -> Result<JsValue, JsValue> {220 let value = mrlyrs::life::single_seed(rule, steps).map_err(hand::throw)?;221 hand::tensor_to_js(&value)222}223224/// Generates the sequence's values up to the limit.225#[wasm_bindgen]226pub fn source_sequence(seq: &Source, limit: usize) -> Result<Vec<usize>, JsValue> {227 let value = mrlyrs::life::source::sequence(seq.inner, limit).map_err(hand::throw)?;228 Ok(value)229}230231/// Advances one row one generation, a constant-0 boundary unless the edges wrap.232#[wasm_bindgen]233pub fn step(row: &[u8], rule: u8, wrap: bool) -> Result<Vec<u8>, JsValue> {234 let value = mrlyrs::life::step(row, rule, wrap).map_err(hand::throw)?;235 Ok(value)236}237238/// Returns whether a rule is surjective on bi-infinite lines, by the de Bruijn subset walk from the full node set.239#[wasm_bindgen]240pub fn surjective(rule: u8) -> Result<bool, JsValue> {241 let value = mrlyrs::life::surjective(rule);242 Ok(value)243}244245/// Tiles every frame n by n to reach at least min_canvas a side, unchanged when already there.246#[wasm_bindgen]247pub fn tessellate(grids: JsValue, min_canvas: usize) -> Result<JsValue, JsValue> {248 let grids = hand::list_from_js(&grids, hand::cell2d_from_js)?;249 let value = mrlyrs::life::tessellate(&grids, min_canvas).map_err(hand::throw)?;250 hand::list_to_js(&value, hand::cell2d_to_js)251}252253/// Returns the rules a rule reaches under left-right reflection and conjugation, Wolfram's equivalence, in ascending order.254#[wasm_bindgen]255pub fn wolfram_class(rule: u8) -> Result<Vec<u8>, JsValue> {256 let value = mrlyrs::life::wolfram_class(rule);257 Ok(value)258}259260/// The rulebook of a life run.261#[wasm_bindgen]262pub struct Config {263 inner: mrlyrs::life::Config,264}265266#[wasm_bindgen]267impl Config {268 /// Reads the Config from its plain data.269 #[wasm_bindgen(js_name = "from")]270 pub fn from_plain(data: JsValue) -> Result<Config, JsValue> {271 Ok(Config { inner: hand::from_js(&data)? })272 }273 /// Writes the Config as plain data.274 #[wasm_bindgen(js_name = "toJSON")]275 pub fn to_plain(&self) -> Result<JsValue, JsValue> {276 hand::to_js(&self.inner)277 }278 /// The neighborhood mask.279 #[wasm_bindgen(getter)]280 pub fn mask(&self) -> Result<JsValue, JsValue> {281 let value = self.inner.mask.clone();282 hand::cell2d_to_js(&value)283 }284 #[wasm_bindgen(setter)]285 pub fn set_mask(&mut self, value: JsValue) -> Result<(), JsValue> {286 let value = hand::cell2d_from_js(&value)?;287 self.inner.mask = value;288 Ok(())289 }290 /// The neighbor counts that create a cell.291 #[wasm_bindgen(getter)]292 pub fn birth(&self) -> Result<Counts, JsValue> {293 let value = self.inner.birth.clone();294 Ok(Counts { inner: value })295 }296 #[wasm_bindgen(setter)]297 pub fn set_birth(&mut self, value: &Counts) -> Result<(), JsValue> {298 self.inner.birth = value.inner.clone();299 Ok(())300 }301 /// The neighbor counts that keep a cell.302 #[wasm_bindgen(getter)]303 pub fn survive(&self) -> Result<Counts, JsValue> {304 let value = self.inner.survive.clone();305 Ok(Counts { inner: value })306 }307 #[wasm_bindgen(setter)]308 pub fn set_survive(&mut self, value: &Counts) -> Result<(), JsValue> {309 self.inner.survive = value.inner.clone();310 Ok(())311 }312 /// The edge policy.313 #[wasm_bindgen(getter)]314 pub fn boundary(&self) -> Result<JsValue, JsValue> {315 let value = self.inner.boundary;316 hand::to_js(&value)317 }318 #[wasm_bindgen(setter)]319 pub fn set_boundary(&mut self, value: JsValue) -> Result<(), JsValue> {320 let value = hand::from_js::<mrlyrs::life::Boundary>(&value)?;321 self.inner.boundary = value;322 Ok(())323 }324 /// The generation cap.325 #[wasm_bindgen(getter)]326 pub fn max_generations(&self) -> Result<usize, JsValue> {327 let value = self.inner.max_generations;328 Ok(value)329 }330 #[wasm_bindgen(setter)]331 pub fn set_max_generations(&mut self, value: usize) -> Result<(), JsValue> {332 self.inner.max_generations = value;333 Ok(())334 }335 /// The tiling factor applied to the seed.336 #[wasm_bindgen(getter)]337 pub fn grid_size(&self) -> Result<usize, JsValue> {338 let value = self.inner.grid_size;339 Ok(value)340 }341 #[wasm_bindgen(setter)]342 pub fn set_grid_size(&mut self, value: usize) -> Result<(), JsValue> {343 self.inner.grid_size = value;344 Ok(())345 }346 /// The dead border added around the seed.347 #[wasm_bindgen(getter)]348 pub fn padding(&self) -> Result<usize, JsValue> {349 let value = self.inner.padding;350 Ok(value)351 }352 #[wasm_bindgen(setter)]353 pub fn set_padding(&mut self, value: usize) -> Result<(), JsValue> {354 self.inner.padding = value;355 Ok(())356 }357 /// Returns the largest neighbor count the mask can reach.358 pub fn budget(&self) -> Result<usize, JsValue> {359 let value = self.inner.budget();360 Ok(value)361 }362 /// Resolves the birth and survive counts against the mask's budget.363 pub fn counts(&self) -> Result<JsValue, JsValue> {364 let value = self.inner.counts().map_err(hand::throw)?;365 Ok(hand::tuple_to_js(&[hand::typed(&(value.0)[..]), hand::typed(&(value.1)[..])]))366 }367 /// Builds a config with a constant boundary, a 64-generation cap, no tiling and no padding.368 #[wasm_bindgen(constructor)]369 pub fn new(mask: JsValue, birth: &Counts, survive: &Counts) -> Result<Config, JsValue> {370 let mask = hand::cell2d_from_js(&mask)?;371 let value = mrlyrs::life::Config::new(mask, birth.inner.clone(), survive.inner.clone());372 Ok(Config { inner: value })373 }374}375376/// The neighbor counts one side of a rule fires on.377#[wasm_bindgen]378pub struct Counts {379 inner: mrlyrs::life::Counts,380}381382#[wasm_bindgen]383impl Counts {384 /// Reads the Counts from its plain data.385 #[wasm_bindgen(js_name = "from")]386 pub fn from_plain(data: JsValue) -> Result<Counts, JsValue> {387 Ok(Counts { inner: hand::from_js(&data)? })388 }389 /// Writes the Counts as plain data.390 #[wasm_bindgen(js_name = "toJSON")]391 pub fn to_plain(&self) -> Result<JsValue, JsValue> {392 hand::to_js(&self.inner)393 }394 /// Builds the counts a sequence lays down, keeping zeros and ones on request.395 pub fn drawn(seq: &Source, zeros: bool, ones: bool) -> Result<Counts, JsValue> {396 let value = mrlyrs::life::Counts::drawn(seq.inner, zeros, ones);397 Ok(Counts { inner: value })398 }399 /// Spells the counts outright.400 pub fn list(counts: Vec<usize>) -> Result<Counts, JsValue> {401 let value = mrlyrs::life::Counts::list(counts);402 Ok(Counts { inner: value })403 }404 /// Returns the counts, a drawn side resolved against the mask's neighbor budget.405 pub fn values(&self, budget: usize) -> Result<Vec<usize>, JsValue> {406 let value = self.inner.values(budget).map_err(hand::throw)?;407 Ok(value)408 }409}410411/// The recorded run of one seed.412#[wasm_bindgen]413pub struct Life {414 inner: mrlyrs::life::Life,415}416417#[wasm_bindgen]418impl Life {419 /// Reads the Life from its plain data.420 #[wasm_bindgen(js_name = "from")]421 pub fn from_plain(data: JsValue) -> Result<Life, JsValue> {422 Ok(Life { inner: hand::from_js(&data)? })423 }424 /// Writes the Life as plain data.425 #[wasm_bindgen(js_name = "toJSON")]426 pub fn to_plain(&self) -> Result<JsValue, JsValue> {427 hand::to_js(&self.inner)428 }429 /// Every generation in order.430 #[wasm_bindgen(getter)]431 pub fn grids(&self) -> Result<JsValue, JsValue> {432 let value = self.inner.grids.clone();433 hand::list_to_js(&value, hand::cell2d_to_js)434 }435 #[wasm_bindgen(setter)]436 pub fn set_grids(&mut self, value: JsValue) -> Result<(), JsValue> {437 let value = hand::list_from_js(&value, hand::cell2d_from_js)?;438 self.inner.grids = value;439 Ok(())440 }441 /// The run's ending.442 #[wasm_bindgen(getter)]443 pub fn fate(&self) -> Result<JsValue, JsValue> {444 let value = self.inner.fate;445 hand::to_js(&value)446 }447 #[wasm_bindgen(setter)]448 pub fn set_fate(&mut self, value: JsValue) -> Result<(), JsValue> {449 let value = hand::from_js::<mrlyrs::life::Fate>(&value)?;450 self.inner.fate = value;451 Ok(())452 }453 /// The number of recorded generations.454 #[wasm_bindgen(getter)]455 pub fn count(&self) -> Result<usize, JsValue> {456 let value = self.inner.count;457 Ok(value)458 }459 #[wasm_bindgen(setter)]460 pub fn set_count(&mut self, value: usize) -> Result<(), JsValue> {461 self.inner.count = value;462 Ok(())463 }464 /// The cycle length when the fate is a loop, else zero.465 #[wasm_bindgen(getter)]466 pub fn loop_length(&self) -> Result<usize, JsValue> {467 let value = self.inner.loop_length;468 Ok(value)469 }470 #[wasm_bindgen(setter)]471 pub fn set_loop_length(&mut self, value: usize) -> Result<(), JsValue> {472 self.inner.loop_length = value;473 Ok(())474 }475 /// Returns the final grid, or None when the run is empty.476 pub fn last(&self) -> Result<JsValue, JsValue> {477 let value = self.inner.last();478 hand::option_to_js(value, hand::cell2d_to_js)479 }480}481482/// A life rule: the birth and survival counts and whether the edge wraps.483#[wasm_bindgen]484pub struct Rule {485 inner: mrlyrs::life::Rule,486}487488#[wasm_bindgen]489impl Rule {490 /// Reads the Rule from its plain data.491 #[wasm_bindgen(js_name = "from")]492 pub fn from_plain(data: JsValue) -> Result<Rule, JsValue> {493 Ok(Rule { inner: hand::from_js(&data)? })494 }495 /// Writes the Rule as plain data.496 #[wasm_bindgen(js_name = "toJSON")]497 pub fn to_plain(&self) -> Result<JsValue, JsValue> {498 hand::to_js(&self.inner)499 }500 /// The neighbor counts that create a cell, listed or drawn from a sequence.501 #[wasm_bindgen(getter)]502 pub fn birth(&self) -> Result<Counts, JsValue> {503 let value = self.inner.birth.clone();504 Ok(Counts { inner: value })505 }506 #[wasm_bindgen(setter)]507 pub fn set_birth(&mut self, value: &Counts) -> Result<(), JsValue> {508 self.inner.birth = value.inner.clone();509 Ok(())510 }511 /// The neighbor counts that keep a cell, listed or drawn from a sequence.512 #[wasm_bindgen(getter)]513 pub fn survive(&self) -> Result<Counts, JsValue> {514 let value = self.inner.survive.clone();515 Ok(Counts { inner: value })516 }517 #[wasm_bindgen(setter)]518 pub fn set_survive(&mut self, value: &Counts) -> Result<(), JsValue> {519 self.inner.survive = value.inner.clone();520 Ok(())521 }522 /// Whether the edge wraps, false unless said.523 #[wasm_bindgen(getter)]524 pub fn wrap(&self) -> Result<bool, JsValue> {525 let value = self.inner.wrap;526 Ok(value)527 }528 #[wasm_bindgen(setter)]529 pub fn set_wrap(&mut self, value: bool) -> Result<(), JsValue> {530 self.inner.wrap = value;531 Ok(())532 }533 /// Returns the edge policy the rule runs under.534 pub fn boundary(&self) -> Result<JsValue, JsValue> {535 let value = self.inner.boundary();536 hand::to_js(&value)537 }538 /// Folds a decoded value to its canonical form, or an error for one outside the kind.539 pub fn checked(&self) -> Result<Rule, JsValue> {540 let value = <mrlyrs::life::Rule as mrlyrs::math::name::Named>::checked(self.inner.clone()).map_err(hand::throw)?;541 Ok(Rule { inner: value })542 }543 /// Builds a life config running this rule over a neighborhood mask.544 pub fn config(&self, mask: JsValue) -> Result<Config, JsValue> {545 let mask = hand::cell2d_from_js(&mask)?;546 let value = self.inner.config(mask);547 Ok(Config { inner: value })548 }549 /// Reads a filename back into the value, or an error.550 pub fn from_file(text: &str) -> Result<Rule, JsValue> {551 let value = <mrlyrs::life::Rule as mrlyrs::math::name::Named>::from_file(text).map_err(hand::throw)?;552 Ok(Rule { inner: value })553 }554 /// Reads a JSON object into its canonical value, or an error naming the broken key.555 pub fn from_json(text: &str) -> Result<Rule, JsValue> {556 let value = <mrlyrs::life::Rule as mrlyrs::math::name::Named>::from_json(text).map_err(hand::throw)?;557 Ok(Rule { inner: value })558 }559 /// Reads a path and query string back into the value, or an error.560 pub fn from_url(text: &str) -> Result<Rule, JsValue> {561 let value = <mrlyrs::life::Rule as mrlyrs::math::name::Named>::from_url(text).map_err(hand::throw)?;562 Ok(Rule { inner: value })563 }564 /// Builds a rule from its counts and edge policy, listed counts folded to a sorted set.565 #[wasm_bindgen(constructor)]566 pub fn new(birth: &Counts, survive: &Counts, wrap: bool) -> Result<Rule, JsValue> {567 let value = mrlyrs::life::Rule::new(birth.inner.clone(), survive.inner.clone(), wrap);568 Ok(Rule { inner: value })569 }570 /// Reads the rule out of a life config.571 pub fn of(config: &Config) -> Result<Rule, JsValue> {572 let value = mrlyrs::life::Rule::of(&config.inner);573 Ok(Rule { inner: value })574 }575 /// Prints the kind and the `key=value` pairs joined by underscores, lists in brackets, or an error when the name does not read back.576 pub fn to_file(&self) -> Result<String, JsValue> {577 let value = <mrlyrs::life::Rule as mrlyrs::math::name::Named>::to_file(&self.inner).map_err(hand::throw)?;578 Ok(value)579 }580 /// Prints the first eight hex digits of the sha256 of the canonical JSON.581 pub fn to_id(&self) -> Result<String, JsValue> {582 let value = <mrlyrs::life::Rule as mrlyrs::math::name::Named>::to_id(&self.inner);583 Ok(value)584 }585 /// Prints the canonical JSON object.586 pub fn to_json(&self) -> Result<String, JsValue> {587 let value = <mrlyrs::life::Rule as mrlyrs::math::name::Named>::to_json(&self.inner);588 Ok(value)589 }590 /// Prints the kind and the keys as a line of prose for pages, or an error when the name does not read back.591 pub fn to_mrly(&self) -> Result<String, JsValue> {592 let value = <mrlyrs::life::Rule as mrlyrs::math::name::Named>::to_mrly(&self.inner).map_err(hand::throw)?;593 Ok(value)594 }595 /// Prints the kind as a path and the keys as a query string, lists comma-joined, or an error when the name does not read back.596 pub fn to_url(&self) -> Result<String, JsValue> {597 let value = <mrlyrs::life::Rule as mrlyrs::math::name::Named>::to_url(&self.inner).map_err(hand::throw)?;598 Ok(value)599 }600}601602/// A named source of neighbor-count values.603#[wasm_bindgen]604pub struct Source {605 inner: mrlyrs::life::Source,606}607608#[wasm_bindgen]609impl Source {610 /// Reads the Source from its plain data.611 #[wasm_bindgen(js_name = "from")]612 pub fn from_plain(data: JsValue) -> Result<Source, JsValue> {613 Ok(Source { inner: hand::from_js(&data)? })614 }615 /// Writes the Source as plain data.616 #[wasm_bindgen(js_name = "toJSON")]617 pub fn to_plain(&self) -> Result<JsValue, JsValue> {618 hand::to_js(&self.inner)619 }620 /// Returns every fixed sequence, the seeded and coded families excluded.621 pub fn all() -> Result<JsValue, JsValue> {622 let value = mrlyrs::life::Source::all();623 hand::list_to_js(&value, |x1| Ok(JsValue::from(Source { inner: *x1 })))624 }625 /// Returns the seventeen mrly design families: the grid, the four classics and their antis.626 pub fn designs() -> Result<JsValue, JsValue> {627 let value = mrlyrs::life::Source::designs();628 hand::list_to_js(&value, |x1| Ok(JsValue::from(Source { inner: *x1 })))629 }630 /// Returns whether the sequence is a seeded random draw.631 pub fn is_random(&self) -> Result<bool, JsValue> {632 let value = self.inner.is_random();633 Ok(value)634 }635 /// Returns the sequence's parseable name, the one string that regenerates it.636 pub fn name(&self) -> Result<String, JsValue> {637 let value = self.inner.name();638 Ok(value)639 }640 /// Returns the six number sequences, the random one listed under seed zero.641 pub fn numbers() -> Result<JsValue, JsValue> {642 let value = mrlyrs::life::Source::numbers();643 hand::list_to_js(&value, |x1| Ok(JsValue::from(Source { inner: *x1 })))644 }645 /// Returns the sequence's OEIS id, or None off the encyclopedia.646 pub fn oeis(&self) -> Result<JsValue, JsValue> {647 let value = self.inner.oeis();648 hand::to_js(&value)649 }650 /// Parses a sequence name back to its source.651 pub fn parse(name: &str) -> Result<Source, JsValue> {652 let value = mrlyrs::life::Source::parse(name).map_err(hand::throw)?;653 Ok(Source { inner: value })654 }655 /// Reads a canonical name off the front of the text, returning the tail left over.656 pub fn read(text: &str) -> Result<JsValue, JsValue> {657 let value = mrlyrs::life::Source::read(text);658 hand::option_to_js(value.as_ref(), |x1| Ok(hand::tuple_to_js(&[JsValue::from(Source { inner: x1.0 }), hand::to_js(&x1.1)?])))659 }660}661662/// The edge policy of a life grid.663#[wasm_bindgen]664pub struct Boundary {}665666#[wasm_bindgen]667impl Boundary {668 /// Returns every Boundary in canonical order.669 pub fn all() -> Result<JsValue, JsValue> {670 let value = mrlyrs::life::Boundary::all();671 hand::to_js(&value)672 }673 /// Returns whether the edges wrap.674 pub fn wrap(boundary: JsValue) -> Result<bool, JsValue> {675 let boundary = hand::from_js::<mrlyrs::life::Boundary>(&boundary)?;676 let value = boundary.wrap();677 Ok(value)678 }679}680681/// The ending of a life run.682#[wasm_bindgen]683pub struct Fate {}684685#[wasm_bindgen]686impl Fate {687 /// Returns every Fate in canonical order.688 pub fn all() -> Result<JsValue, JsValue> {689 let value = mrlyrs::life::Fate::all();690 hand::to_js(&value)691 }692}