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}