diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d930cd6..d1b4660 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,5 +1,4 @@ version: 2 - updates: - package-ecosystem: cargo directory: / @@ -13,3 +12,7 @@ updates: directory: /rstm schedule: interval: weekly + - package-ecosystem: cargo + directory: /rstm-core + schedule: + interval: weekly diff --git a/.github/workflows/crates.yml b/.github/workflows/crates.yml index 2f5a882..3673993 100644 --- a/.github/workflows/crates.yml +++ b/.github/workflows/crates.yml @@ -16,9 +16,45 @@ on: workflow_dispatch: jobs: + independents: + env: + CRATE_NAME: ${{ github.event.repository.name }}-${{ matrix.suffix }} + name: Publish (${{ matrix.suffix }}) + runs-on: ubuntu-latest + strategy: + matrix: + suffix: [ core ] + steps: + - uses: actions/checkout@v4 + - name: cache + uses: actions/cache@v4 + with: + key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} + path: | + ~/.cargo/registry + ~/.cargo/git + target/debug + target/release + restore-keys: | + cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} + cargo-${{ runner.os }}- + cargo- + - run: cargo publish --all-features -v -p ${{ env.CRATE_NAME }} --token ${{ secrets.CARGO_REGISTRY_TOKEN }} publish: name: Publish (${{ github.event.repository.name }}) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: cache + uses: actions/cache@v4 + with: + key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} + path: | + ~/.cargo/registry + ~/.cargo/git + target/release + restore-keys: | + cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} + cargo-${{ runner.os }}- + cargo- - run: cargo publish --all-features -v -p ${{ github.event.repository.name }} --token ${{ secrets.CARGO_REGISTRY_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c5ba4ca..0ccfc7d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -43,27 +43,19 @@ jobs: - name: cache uses: actions/cache@v4 with: - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: cargo-${{ matrix.toolchain }}-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} path: | ~/.cargo/registry ~/.cargo/git + target/debug target/release - bench: - name: Benchmark - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: setup (rustup) - run: rustup default nightly && rustup update + restore-keys: | + cargo-${{ matrix.toolchain }}-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} + cargo-${{ matrix.toolchain }}-${{ runner.os }}- + cargo-${{ matrix.toolchain }}- + cargo- - name: cargo (bench) + if: matrix.toolchain == 'nightly' run: cargo bench --features full -v --workspace - test: - name: Test - strategy: - matrix: - toolchain: [ stable, nightly ] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: rustup default ${{ matrix.toolchain }} && rustup update - - run: cargo test --features full -v --workspace + - name: cargo test (workspace)[full] + run: cargo test -v --workspace -F full diff --git a/Cargo.toml b/Cargo.toml index 5888613..868998c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] default-members = [ - "rstm" + "rstm", ] exclude = [ @@ -9,13 +9,17 @@ exclude = [ members = [ "rstm", + "core", ] resolver = "2" [workspace.dependencies] +lazy_static = "1" +paste = "1" smart-default = "0.7" +thiserror = "1" [workspace.package] authors = ["Joe McCain III ",] @@ -27,7 +31,7 @@ keywords = [ ] license = "Apache-2.0" readme = "README.md" repository = "https://github.com/FL03/rstm.git" -version = "0.0.1" +version = "0.0.2" [profile.dev] opt-level = 0 diff --git a/core/Cargo.toml b/core/Cargo.toml new file mode 100644 index 0000000..1cab80d --- /dev/null +++ b/core/Cargo.toml @@ -0,0 +1,76 @@ +[package] +authors.workspace = true +build = "build.rs" +categories.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +license.workspace = true +name = "rstm-core" +readme.workspace = true +repository.workspace = true +version.workspace = true + +[features] +default = [] + +full = [ + "default", + "serde", + "tracing", +] + +# ********* [FF] Dependencies ********* +alloc = [ + "serde?/alloc", +] + +serde = [ + "dep:serde", +] + +tracing = [ + "dep:tracing", +] + +# ********* [FF] Environments ********* +# std = [ +# "alloc", +# "serde?/std", +# "strum/std", +# ] + +[lib] +bench = true +crate-type = ["cdylib", "rlib"] +doctest = false +test = true + +[dependencies] +thiserror.workspace = true +paste.workspace = true + +[dependencies.serde] +# default-features = false +features = ["derive"] +optional = true +version = "1" + +[dependencies.strum] +# default-features = false +features = ["derive"] +version = "0.26" + +[dependencies.tracing] +features = [] +optional = true +version = "0.1" + +[dev-dependencies] +lazy_static.workspace = true +tracing-subscriber = { features = [], version = "0.3" } + +[package.metadata.docs.rs] +all-features = true +rustc-args = ["--cfg", "docsrs"] diff --git a/core/build.rs b/core/build.rs new file mode 100644 index 0000000..940a4ce --- /dev/null +++ b/core/build.rs @@ -0,0 +1,8 @@ +/* + Appellation: build + Contrib: FL03 +*/ + +fn main() { + println!("cargo::rustc-check-cfg=cfg(no_std)"); +} diff --git a/rstm/src/error.rs b/core/src/error.rs similarity index 50% rename from rstm/src/error.rs rename to core/src/error.rs index 6e1e192..02c87a1 100644 --- a/rstm/src/error.rs +++ b/core/src/error.rs @@ -7,37 +7,43 @@ Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, strum::VariantNames, thiserror::Error, )] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub enum FsmError { - #[error("[IndexError] Out of Bounds: {0}")] - IndexOutOfBounds(String), +pub enum Error { + #[error("[IndexError] Out of Bounds: {index} is out of bounds for a length of {len}")] + IndexOutOfBounds { index: usize, len: usize }, #[error("[StateError] Invalid State: {0}")] InvalidState(String), - #[error("[StateError] State Not Found: {0}")] - StateNotFound(String), + #[error("[StateError] State Not Found")] + StateNotFound, #[error("Transformation error: {0}")] TransformationError(String), #[error("Unknown error: {0}")] Unknown(String), } -impl FsmError { - pub fn index_out_of_bounds(err: impl ToString) -> Self { - FsmError::IndexOutOfBounds(err.to_string()) +impl Error { + pub fn index_out_of_bounds(index: usize, len: usize) -> Self { + Error::IndexOutOfBounds { index, len } } pub fn invalid_state(err: impl ToString) -> Self { - FsmError::InvalidState(err.to_string()) + Error::InvalidState(err.to_string()) } - pub fn state_not_found(err: impl ToString) -> Self { - FsmError::StateNotFound(err.to_string()) + pub fn state_not_found() -> Self { + Error::StateNotFound } pub fn transformation_error(message: impl ToString) -> Self { - FsmError::TransformationError(message.to_string()) + Error::TransformationError(message.to_string()) } pub fn unknown(message: impl ToString) -> Self { - FsmError::Unknown(message.to_string()) + Error::Unknown(message.to_string()) + } +} + +impl From<&str> for Error { + fn from(err: &str) -> Self { + Error::Unknown(err.to_string()) } } diff --git a/core/src/lib.rs b/core/src/lib.rs new file mode 100644 index 0000000..b614f62 --- /dev/null +++ b/core/src/lib.rs @@ -0,0 +1,39 @@ +/* + Appellation: rstm-core + Contrib: FL03 +*/ +//! # rstm-core +//! + +// #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "alloc")] +extern crate alloc; + +#[doc(inline)] +pub use self::{ + error::Error, ops::prelude::*, rules::prelude::*, state::State, tape::StdTape, + traits::prelude::*, types::prelude::*, +}; + +#[macro_use] +pub(crate) mod macros; +#[macro_use] +pub(crate) mod seal; + +pub mod error; +pub mod ops; +pub mod rules; +pub mod state; +pub mod tape; +pub mod traits; +pub mod types; + +pub mod prelude { + pub use crate::error::Error; + pub use crate::ops::prelude::*; + pub use crate::rules::prelude::*; + pub use crate::state::prelude::*; + pub use crate::tape::prelude::*; + pub use crate::traits::prelude::*; + pub use crate::types::prelude::*; +} diff --git a/core/src/macros.rs b/core/src/macros.rs new file mode 100644 index 0000000..97f981e --- /dev/null +++ b/core/src/macros.rs @@ -0,0 +1,7 @@ +/* + Appellation: macros + Contrib: FL03 +*/ + +#[macro_use] +pub mod states; diff --git a/core/src/macros/states.rs b/core/src/macros/states.rs new file mode 100644 index 0000000..fc539d9 --- /dev/null +++ b/core/src/macros/states.rs @@ -0,0 +1,4 @@ +/* + Appellation: states + Contrib: FL03 +*/ diff --git a/core/src/ops/mod.rs b/core/src/ops/mod.rs new file mode 100644 index 0000000..d52e805 --- /dev/null +++ b/core/src/ops/mod.rs @@ -0,0 +1,17 @@ +/* + Appellation: ops + Contrib: FL03 +*/ +//! # Operations +//! +//! Overloadable operations used throughout the `rstm` crate. +#[doc(inline)] +pub use self::transform::*; + +#[doc(hidden)] +pub mod shift; +pub mod transform; + +pub(crate) mod prelude { + pub use super::transform::*; +} diff --git a/core/src/ops/shift.rs b/core/src/ops/shift.rs new file mode 100644 index 0000000..e0e8f9e --- /dev/null +++ b/core/src/ops/shift.rs @@ -0,0 +1,10 @@ +/* + Appellation: shift + Contrib: FL03 +*/ + +pub trait Shift { + type Output; + + fn shift(&self, tape: &T) -> Self::Output; +} diff --git a/core/src/ops/transform.rs b/core/src/ops/transform.rs new file mode 100644 index 0000000..4ec945c --- /dev/null +++ b/core/src/ops/transform.rs @@ -0,0 +1,16 @@ +/* + Appellation: transform + Contrib: FL03 +*/ + +/// The [`Transform`] trait generically describes objects capable of applying some transformation. +/// From a "rustic" point of view, the trait simply provides an additional reference point for +/// the `map` method, which is a method that applies a function to a value and returns a new value. +/// +/// [`Transform::transform`] is a method that takes a reference to `self` and a value of type `T` +/// and returns a value of type [`Transform::Output`]. +pub trait Transform { + type Output; + + fn transform(&self, delta: T) -> Self::Output; +} diff --git a/core/src/rules/entry.rs b/core/src/rules/entry.rs new file mode 100644 index 0000000..92be88d --- /dev/null +++ b/core/src/rules/entry.rs @@ -0,0 +1,24 @@ +/* + Appellation: entry + Contrib: FL03 +*/ +pub use crate::rules::{Head, Tail}; + +pub struct Entry<'a, Q, S> { + key: &'a mut Head, + value: &'a mut Tail, +} + +impl<'a, Q, S> Entry<'a, Q, S> { + pub fn new(key: &'a mut Head, value: &'a mut Tail) -> Self { + Self { key, value } + } + + pub fn key(&self) -> &Head { + &self.key + } + + pub fn value(&self) -> &Tail { + &self.value + } +} diff --git a/rstm/src/rules/instruction.rs b/core/src/rules/instruction.rs similarity index 74% rename from rstm/src/rules/instruction.rs rename to core/src/rules/instruction.rs index b93c56e..6f0673c 100644 --- a/rstm/src/rules/instruction.rs +++ b/core/src/rules/instruction.rs @@ -17,31 +17,39 @@ impl Instruction { pub fn new() -> InstructionBuilder { InstructionBuilder::new() } - + /// Returns a reference to the [head](Head) of the [instruction](Instruction) pub const fn head(&self) -> &Head { &self.head } - + /// Returns a mutable reference to the [head](Head) of the [instruction](Instruction) + pub fn head_mut(&mut self) -> &mut Head { + &mut self.head + } + /// Returns a reference to the [tail](Tail) of the [instruction](Instruction) pub const fn tail(&self) -> &Tail { &self.tail } - + /// Returns a mutable reference to the [tail](Tail) of the [instruction](Instruction) + pub fn tail_mut(&mut self) -> &mut Tail { + &mut self.tail + } + /// Returns the direction the [head](Head) is instructed to move pub fn direction(&self) -> Direction { - self.tail.direction() + self.tail().direction() } - - pub const fn state(&self) -> &State { - &self.head.state + /// Returns the current [state](State) of the [head](Head) + pub fn state(&self) -> State<&'_ Q> { + self.head().get_state() } - + /// Returns the current symbol of the [head](Head) pub const fn symbol(&self) -> &S { self.head().symbol() } - - pub const fn next_state(&self) -> &State { + /// Returns the next [state](State) the agent is instructed to move to + pub fn next_state(&self) -> State<&'_ Q> { self.tail().next_state() } - + /// Returns the symbol the [head](Head) is instructed to write pub const fn write_symbol(&self) -> &S { self.tail().write_symbol() } diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs new file mode 100644 index 0000000..737ecbc --- /dev/null +++ b/core/src/rules/mod.rs @@ -0,0 +1,167 @@ +/* + Appellation: programs + Contrib: FL03 +*/ +#[doc(inline)] +pub use self::{ + instruction::*, + parts::{Head, Tail}, + program::*, +}; + +pub(crate) mod instruction; +pub(crate) mod program; + +#[doc(hidden)] +pub mod entry; + +pub mod parts { + pub use self::{head::*, tail::*}; + + pub(crate) mod head; + pub(crate) mod tail; +} + +pub(crate) mod prelude { + pub use super::instruction::Instruction; + pub use super::parts::{Head, Tail}; + pub use super::program::Program; +} + +use crate::{Direction, State, Symbolic}; + +pub trait Rule { + type Elem; + type State; +} + +pub trait Transition +where + S: Symbolic, +{ + fn direction(&self) -> Direction; + + fn current_state(&self) -> State<&'_ Q>; + + fn next_state(&self) -> State<&'_ Q>; + + fn symbol(&self) -> &S; + + fn write_symbol(&self) -> &S; +} + +pub trait Header { + fn current_state(&self) -> State<&'_ Q>; + + fn symbol(&self) -> &S; +} + +pub trait Directive { + fn direction(&self) -> Direction; + + fn next_state(&self) -> State<&'_ Q>; + + fn write_symbol(&self) -> &S; +} + +/* + ************* Implementations ************* +*/ + +impl Transition for A +where + A: Header + Directive, + S: Symbolic, +{ + fn direction(&self) -> Direction { + self.direction() + } + + fn current_state(&self) -> State<&'_ Q> { + self.current_state() + } + + fn next_state(&self) -> State<&'_ Q> { + self.next_state() + } + + fn symbol(&self) -> &S { + self.symbol() + } + + fn write_symbol(&self) -> &S { + self.write_symbol() + } +} + +impl Header for Instruction { + fn current_state(&self) -> State<&'_ Q> { + self.head.state.to_ref() + } + + fn symbol(&self) -> &S { + &self.symbol() + } +} + +impl Directive for Instruction { + fn direction(&self) -> Direction { + self.direction() + } + + fn next_state(&self) -> State<&'_ Q> { + self.tail().next_state() + } + + fn write_symbol(&self) -> &S { + &self.write_symbol() + } +} + +impl Header for crate::Head { + fn current_state(&self) -> State<&'_ Q> { + self.state().to_ref() + } + + fn symbol(&self) -> &S { + &self.symbol + } +} + +impl Directive for crate::Tail { + fn direction(&self) -> Direction { + self.direction + } + + fn next_state(&self) -> State<&'_ Q> { + self.next_state() + } + + fn write_symbol(&self) -> &S { + &self.write_symbol() + } +} + +impl Header for (State, S) { + fn current_state(&self) -> State<&'_ Q> { + self.0.to_ref() + } + + fn symbol(&self) -> &S { + &self.1 + } +} + +impl Directive for (Direction, State, S) { + fn direction(&self) -> Direction { + self.0 + } + + fn next_state(&self) -> State<&'_ Q> { + self.1.to_ref() + } + + fn write_symbol(&self) -> &S { + &self.2 + } +} diff --git a/rstm/src/types/head.rs b/core/src/rules/parts/head.rs similarity index 64% rename from rstm/src/types/head.rs rename to core/src/rules/parts/head.rs index cfb2c3b..3fb272e 100644 --- a/rstm/src/types/head.rs +++ b/core/src/rules/parts/head.rs @@ -5,14 +5,25 @@ use crate::state::State; /// The head of a turing machine generally speaks to the current state and symbol of the machine -/// w.r.t. the [tape](crate::types::Tape). Currently, the head simply stores a reference to the -/// +/// w.r.t. the [tape](crate::Tape). #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Head { + #[cfg_attr( + feature = "serde", + serde( + flatten, + alias = "state", + alias = "current_state", + alias = "head_state" + ) + )] pub state: State, + #[cfg_attr( + feature = "serde", + serde(flatten, alias = "symbol", alias = "current_symbol", alias = "value") + )] pub symbol: S, - // pub(crate) _ptr: , } impl Head { @@ -34,6 +45,7 @@ impl Head { pub fn as_mut_tuple(&mut self) -> (&mut State, &mut S) { (&mut self.state, &mut self.symbol) } + /// Updates the current [state](State) pub fn set_state(&mut self, state: State) { self.state = state; @@ -43,6 +55,10 @@ impl Head { self.symbol = symbol; } /// Returns a reference to the current [state](State) + pub fn get_state(&self) -> State<&'_ Q> { + self.state.to_ref() + } + pub const fn state(&self) -> &State { &self.state } @@ -67,6 +83,39 @@ impl Head { self.symbol = symbol; } } + + pub fn to_ref<'a>(&'a self) -> Head<&'a Q, &'a S> { + Head { + state: self.state.to_ref(), + symbol: &self.symbol, + } + } + + pub fn to_mut<'a>(&'a mut self) -> Head<&'a mut Q, &'a mut S> { + Head { + state: self.state.to_mut(), + symbol: &mut self.symbol, + } + } +} + +impl<'a, Q, S> Head<&'a Q, &'a S> { + pub fn cloned(&self) -> Head + where + Q: Clone, + S: Clone, + { + Head { + state: self.state.cloned(), + symbol: self.symbol.clone(), + } + } +} + +impl From<(Q, S)> for Head { + fn from((state, symbol): (Q, S)) -> Self { + Self::new(State(state), symbol) + } } impl From<(State, S)> for Head { @@ -74,3 +123,9 @@ impl From<(State, S)> for Head { Self::new(state, symbol) } } + +impl From> for (State, S) { + fn from(head: Head) -> Self { + head.into_tuple() + } +} diff --git a/core/src/rules/parts/tail.rs b/core/src/rules/parts/tail.rs new file mode 100644 index 0000000..1c89fc9 --- /dev/null +++ b/core/src/rules/parts/tail.rs @@ -0,0 +1,187 @@ +/* + Appellation: tail + Contrib: FL03 +*/ +pub use self::builder::TailBuilder; + +use crate::{Direction, Head, State}; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Tail { + pub direction: Direction, + #[cfg_attr( + feature = "serde", + serde(flatten, alias = "state", alias = "next_state") + )] + pub state: State, + #[cfg_attr( + feature = "serde", + serde(flatten, alias = "symbol", alias = "write_symbol") + )] + pub symbol: S, +} + +impl Tail { + pub fn new(direction: Direction, State(state): State, symbol: S) -> Self { + Self { + direction, + state: State(state), + symbol, + } + } + + pub fn create() -> TailBuilder { + TailBuilder::new(Direction::Right) + } + /// Returns the direction, state, and symbol as a 3-tuple + pub fn as_tuple(&self) -> (Direction, &State, &S) { + (self.direction, &self.state, &self.symbol) + } + /// Consumes the tail and returns the direction, state, and symbol as a 3-tuple + pub fn into_tuple(self) -> (Direction, State, S) { + (self.direction, self.state, self.symbol) + } + /// Returns the direction the [head](StdHead) is instructed to move + pub fn direction(&self) -> Direction { + self.direction + } + /// Returns the next [state](State) the agent is instructed to move to + pub fn next_state(&self) -> State<&'_ Q> { + self.state.to_ref() + } + /// Returns the symbol the [head](Head) is instructed to write + pub const fn write_symbol(&self) -> &S { + &self.symbol + } + /// Consumes the tail and returns a new instance of the [Head] + pub fn into_head(self) -> Head { + super::Head::new(self.state, self.symbol) + } + /// Returns an instance of the [head](Head) where each element within + /// the created instance is an immutable reference + pub fn to_head_ref<'a>(&'a self) -> Head<&'a Q, &'a S> { + super::Head::new(self.state.to_ref(), &self.symbol) + } + + pub fn to_ref(&self) -> Tail<&'_ Q, &'_ S> { + Tail { + direction: self.direction, + state: self.state.to_ref(), + symbol: &self.symbol, + } + } + + pub fn to_mut(&mut self) -> Tail<&'_ mut Q, &'_ mut S> { + Tail { + direction: self.direction, + state: self.state.to_mut(), + symbol: &mut self.symbol, + } + } + + pub fn into_owned(self) -> Tail + where + Q: Clone, + S: Clone, + { + Tail { + direction: self.direction, + state: self.state, + symbol: self.symbol, + } + } + + pub fn to_owned(&self) -> Tail + where + Q: Clone, + S: Clone, + { + Tail { + direction: self.direction, + state: self.state.to_owned(), + symbol: self.symbol.clone(), + } + } +} + +impl<'a, Q, S> Tail<&'a Q, &'a S> { + pub fn cloned(&self) -> Tail + where + Q: Clone, + S: Clone, + { + Tail { + direction: self.direction, + state: self.state.cloned(), + symbol: self.symbol.clone(), + } + } +} + +impl<'a, Q, S> Tail<&'a mut Q, &'a mut S> { + pub fn cloned(&self) -> Tail + where + Q: Clone, + S: Clone, + { + Tail { + direction: self.direction, + state: self.state.cloned(), + symbol: self.symbol.clone(), + } + } +} + +mod builder { + use super::*; + + pub struct TailBuilder { + direction: Direction, + state: Option>, + symbol: Option, + } + + impl TailBuilder { + pub fn new(direction: Direction) -> Self { + Self { + direction, + state: None, + symbol: None, + } + } + /// Sets the direction + pub fn direction(self, direction: Direction) -> Self { + Self { direction, ..self } + } + /// Sets the next [state](State) + pub fn state(self, State(state): State) -> Self { + Self { + state: Some(State(state)), + ..self + } + } + /// Sets the symbol + pub fn symbol(self, symbol: S) -> Self { + Self { + symbol: Some(symbol), + ..self + } + } + /// Consumes the builder and returns a new instance of the [tail](Tail) + pub fn build(self) -> Result, crate::Error> { + if self.state.is_none() { + return Err("Missing state".into()); + } + + if self.symbol.is_none() { + return Err("Missing symbol".into()); + } + Ok(Tail::new( + self.direction, + self.state.expect("State is required"), + self.symbol.expect("Symbol is required"), + )) + } + } +} diff --git a/rstm/src/rules/program.rs b/core/src/rules/program.rs similarity index 69% rename from rstm/src/rules/program.rs rename to core/src/rules/program.rs index 8a2f111..e3127e4 100644 --- a/rstm/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -11,69 +11,69 @@ type RuleSet = Vec>; #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Program { - initial_state: State, - instructions: RuleSet, + pub initial_state: State, + pub(crate) ruleset: RuleSet, } impl Program { pub fn new(State(initial_state): State) -> Self { Self { initial_state: State(initial_state), - instructions: RuleSet::new(), + ruleset: RuleSet::new(), } } - pub fn from_instructions(instructions: impl IntoIterator>) -> Self + pub fn from_iter(instructions: impl IntoIterator>) -> Self where Q: Default, { Self { initial_state: State::default(), - instructions: RuleSet::from_iter(instructions), + ruleset: RuleSet::from_iter(instructions), } } /// - pub fn with_initial_state(self, initial_state: State) -> Self { + pub fn with_initial_state(self, State(state): State) -> Self { Self { - initial_state, + initial_state: State(state), ..self } } - + /// pub fn with_instructions( self, instructions: impl IntoIterator>, ) -> Self { Self { - instructions: RuleSet::from_iter(instructions), + ruleset: RuleSet::from_iter(instructions), ..self } } - /// Returns an owned reference to the element(s) specified by the index. - pub fn get(&self, idx: I) -> Option<&I::Output> - where - I: core::slice::SliceIndex<[Instruction]>, - { - self.instructions.get(idx) - } /// Returns an owned reference to the initial state of the program. - pub const fn initial_state(&self) -> &State { - &self.initial_state + pub fn initial_state(&self) -> State<&'_ Q> { + self.initial_state.to_ref() } /// Returns a reference to the instructions. pub const fn instructions(&self) -> &RuleSet { - &self.instructions + &self.ruleset } /// Returns a mutable reference to the instructions. pub fn instructions_mut(&mut self) -> &mut RuleSet { - &mut self.instructions + &mut self.ruleset } /// Returns an iterator over the elements. pub fn iter(&self) -> core::slice::Iter> { - self.instructions.iter() + self.ruleset.iter() + } + /// Returns an owned reference to the element(s) specified by the index. + pub fn get(&self, idx: I) -> Option<&I::Output> + where + I: core::slice::SliceIndex<[Instruction]>, + { + self.ruleset.get(idx) } /// Returns a collection of tails for a given head. - pub fn get_head(&self, head: &Head) -> Vec<&Tail> + pub fn get_head(&self, head: &Head) -> Vec> where Q: PartialEq, S: PartialEq, @@ -81,20 +81,28 @@ impl Program { self.iter() .filter_map(|i| { if i.head() == head { - Some(i.tail()) + Some(i.tail().to_ref()) } else { None } }) .collect() } + + pub fn find_head(&self, head: Head<&'_ Q, &'_ S>) -> Option<&Tail> + where + Q: PartialEq, + S: PartialEq, + { + self.iter().find(|i| i.head().to_ref() == head).map(|i| i.tail()) + } } impl From> for Program { fn from(instructions: RuleSet) -> Self { Self { initial_state: State::default(), - instructions, + ruleset: instructions, } } } @@ -106,7 +114,7 @@ where fn from_iter>>(iter: I) -> Self { Self { initial_state: State::default(), - instructions: RuleSet::from_iter(iter), + ruleset: RuleSet::from_iter(iter), } } } @@ -116,6 +124,6 @@ impl IntoIterator for Program { type IntoIter = vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.instructions.into_iter() + self.ruleset.into_iter() } } diff --git a/rstm/src/seal.rs b/core/src/seal.rs similarity index 80% rename from rstm/src/seal.rs rename to core/src/seal.rs index c419d9b..72f553e 100644 --- a/rstm/src/seal.rs +++ b/core/src/seal.rs @@ -10,26 +10,26 @@ //! #[doc(hidden)] -pub(crate) trait Private {} +pub(crate) trait Seal {} /// If this type is pub but not publicly reachable, third parties /// can't name it and can't implement traits using it. #[doc(hidden)] -pub struct Seal; +pub struct Sealer; macro_rules! private { () => { /// This trait is private to implement; this method exists to make it /// impossible to implement outside the crate. #[doc(hidden)] - fn __private__(&self) -> $crate::seal::Seal; + fn __private__(&self) -> $crate::seal::Sealer; }; } macro_rules! seal { () => { - fn __private__(&self) -> $crate::seal::Seal { - $crate::seal::Seal + fn __private__(&self) -> $crate::seal::Sealer { + $crate::seal::Sealer } }; } diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs new file mode 100644 index 0000000..c6e407d --- /dev/null +++ b/core/src/state/mod.rs @@ -0,0 +1,43 @@ +/* + Appellation: state + Contrib: FL03 +*/ +#[doc(inline)] +pub use self::{state::State, states::*}; + +pub(crate) mod state; + +pub(crate) mod states { + #[doc(inline)] + pub use self::{binary::*, halting::*}; + + pub(crate) mod binary; + pub(crate) mod halting; +} + +pub(crate) mod prelude { + + pub use super::state::State; + pub use super::states::*; +} + +#[doc(hidden)] +pub trait RawState { + type Data; +} + +#[doc(hidden)] +pub trait Stateful { + type State: RawState; +} + +/* + ************* Implementations ************* +*/ +impl RawState for State { + type Data = Q; +} + +impl Stateful for State { + type State = State; +} diff --git a/core/src/state/state.rs b/core/src/state/state.rs new file mode 100644 index 0000000..66977b5 --- /dev/null +++ b/core/src/state/state.rs @@ -0,0 +1,223 @@ +/* + Appellation: state + Contrib: FL03 +*/ +use crate::state::Halt; +use std::sync::Arc; +/// +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[repr(transparent)] +pub struct State(pub Q); + +impl State { + pub fn new(state: Q) -> Self { + Self(state) + } + /// Returns an immutable reference to the state. + pub fn as_ref(&self) -> &Q { + &self.0 + } + /// Returns a mutable reference to the state. + pub fn as_mut(&mut self) -> &mut Q { + &mut self.0 + } + /// Consumes and returns the inner value of the [state](State). + pub fn into_inner(self) -> Q { + self.0 + } + + pub fn into_owned(self) -> State + where + Q: Clone, + { + State(self.0.clone()) + } + /// Transforms the state into a shared reference. + pub fn into_shared(self) -> State> { + State(Arc::new(self.0)) + } + /// [State::map] applies a [`Fn`] closure to the state, returing a new state in the process. + /// Essentially, the method sufficiently describes the transformation of the state. + pub fn map(self, f: F) -> State + where + F: Fn(State) -> R, + { + State(f(self)) + } + /// [State::map_mut] applies a [`FnMut`] closure to the state, returing the transformed state. + pub fn map_mut(mut self, f: &mut F) -> State + where + F: FnMut(&mut Q) -> R, + { + State(f(self.as_mut())) + } + /// Maps the state to a new state using a closure that takes the state by value. + pub fn map_once(self, f: F) -> State + where + F: FnOnce(State) -> R, + { + State(f(self)) + } + /// Returns a state with an owned inner value. + pub fn to_owned(&self) -> State + where + Q: Clone, + { + State(self.0.clone()) + } + /// Returns a shared reference to the state. + pub fn to_shared(&self) -> State> + where + Q: Clone, + { + State(Arc::new(self.0.clone())) + } + /// Returns a state with a mutable reference to the inner value. + pub fn to_mut<'a>(&'a mut self) -> State<&'a mut Q> { + State(&mut self.0) + } + /// Returns a state with an owned inner value. + pub fn to_ref<'a>(&'a self) -> State<&'a Q> { + State(&self.0) + } + + /// Returns the `name` of the generic inner type, `Q`. + pub fn inner_type_name(&self) -> &'static str { + core::any::type_name::() + } + /// Returns the `type id` of the generic inner type, `Q`. + pub fn inner_type_id(&self) -> core::any::TypeId + where + Q: 'static, + { + core::any::TypeId::of::() + } +} + +impl State> { + /// Returns a new instance of [State] with a [Halt] sub-state. + pub fn halt(Halt(inner): Halt) -> Self { + Self(Halt(inner)) + } + pub fn is_halt(&self) -> bool { + true + } +} + +impl<'a, Q> State<&'a Q> { + /// Clones the internal state and returning a new instance of [State] + pub fn cloned(&self) -> State + where + Q: Clone, + { + State(self.0.clone()) + } + /// Copies the internal state and returning a new instance of [State] + pub fn copied(&self) -> State + where + Q: Copy, + { + State(*self.0) + } +} + +impl<'a, Q> State<&'a mut Q> { + /// Clones the internal state and returning a new instance of [State] + pub fn cloned(&self) -> State + where + Q: Clone, + { + State(self.0.clone()) + } + /// Copies the internal state and returning a new instance of [State] + pub fn copied(&self) -> State + where + Q: Copy, + { + State(*self.0) + } +} + +impl AsRef for State { + fn as_ref(&self) -> &Q { + &self.0 + } +} + +impl AsMut for State { + fn as_mut(&mut self) -> &mut Q { + &mut self.0 + } +} + +impl core::borrow::Borrow for State { + fn borrow(&self) -> &Q { + &self.0 + } +} + +impl core::borrow::BorrowMut for State { + fn borrow_mut(&mut self) -> &mut Q { + &mut self.0 + } +} + +impl core::ops::Deref for State { + type Target = Q; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl core::ops::DerefMut for State { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +macro_rules! impl_fmt { + ($($trait:ident),*) => { + $( + impl core::fmt::$trait for State + where + Q: core::fmt::$trait, + { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::fmt::$trait::fmt(&self.0, f) + } + } + )* + }; +} + +impl_fmt!(Binary, Display, LowerExp, LowerHex, Octal, UpperExp, UpperHex); + +unsafe impl core::marker::Send for State where Q: core::marker::Send {} + +unsafe impl core::marker::Sync for State where Q: core::marker::Sync {} + +impl core::cmp::PartialEq for State +where + Q: core::cmp::PartialEq, +{ + fn eq(&self, other: &Q) -> bool { + self.0 == *other + } +} + +impl core::cmp::PartialOrd for State +where + Q: core::cmp::PartialOrd, +{ + fn partial_cmp(&self, other: &Q) -> Option { + self.0.partial_cmp(other) + } +} + +impl From for State { + fn from(state: Q) -> Self { + Self(state) + } +} diff --git a/rstm/src/state/states/binary.rs b/core/src/state/states/binary.rs similarity index 92% rename from rstm/src/state/states/binary.rs rename to core/src/state/states/binary.rs index 444f5f5..c667768 100644 --- a/rstm/src/state/states/binary.rs +++ b/core/src/state/states/binary.rs @@ -29,7 +29,7 @@ use crate::State; #[repr(C)] #[strum(serialize_all = "lowercase")] #[strum_discriminants( - name(BinaryStates), + name(BinState), derive( Hash, Ord, @@ -64,10 +64,10 @@ impl BinaryState { } } - pub fn kind(&self) -> BinaryStates { + pub fn kind(&self) -> BinState { match self { - Self::Invalid(_) => BinaryStates::Invalid, - Self::Valid(_) => BinaryStates::Valid, + Self::Invalid(_) => BinState::Invalid, + Self::Valid(_) => BinState::Valid, } } } @@ -80,12 +80,12 @@ impl BinaryState { } } - pub fn state(&self) -> (BinaryStates, &Q) { + pub fn state(&self) -> (BinState, &Q) { (self.kind(), self.as_ref()) } } -impl Default for BinaryStates { +impl Default for BinState { fn default() -> Self { Self::Invalid } diff --git a/core/src/state/states/halting.rs b/core/src/state/states/halting.rs new file mode 100644 index 0000000..537a3bd --- /dev/null +++ b/core/src/state/states/halting.rs @@ -0,0 +1,38 @@ +/* + Appellation: halting + Contrib: FL03 +*/ +use crate::state::State; + +#[doc(hidden)] +pub trait Halter { + const HALT: bool = true; + + private!(); +} +#[doc(hidden)] +pub enum Halting { + Continue(T), + Halt(T), +} + +pub struct Halt(pub T); + +impl Halt { + pub fn new(halt: T) -> Self { + Self(halt) + } + pub fn into_inner(self) -> T { + self.0 + } + pub fn as_ref(&self) -> &T { + &self.0 + } + pub fn as_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl Halter for State> { + seal!(); +} diff --git a/core/src/state/transition.rs b/core/src/state/transition.rs new file mode 100644 index 0000000..a43e9e0 --- /dev/null +++ b/core/src/state/transition.rs @@ -0,0 +1,9 @@ +/* + Appellation: transition + Contrib: FL03 +*/ + +pub struct Entry { + key: Head, + value: Tail, +} \ No newline at end of file diff --git a/core/src/tape/entry.rs b/core/src/tape/entry.rs new file mode 100644 index 0000000..14c4474 --- /dev/null +++ b/core/src/tape/entry.rs @@ -0,0 +1,29 @@ +/* + Appellation: entry + Contrib: FL03 +*/ +#![allow(unused)] +use crate::Instruction; + +pub struct Entry<'a, Q, S> { + key: &'a mut usize, + value: &'a mut Instruction, +} + +impl<'a, Q, S> Entry<'a, Q, S> { + pub fn new(key: &'a mut usize, value: &'a mut Instruction) -> Self { + Self { key, value } + } + + pub fn key(&self) -> &usize { + &self.key + } + + pub fn set_key(&mut self, key: usize) { + *self.key = key; + } + + pub fn set_value(&mut self, value: Instruction) { + *self.value = value; + } +} diff --git a/core/src/tape/iter.rs b/core/src/tape/iter.rs new file mode 100644 index 0000000..ebeb3cc --- /dev/null +++ b/core/src/tape/iter.rs @@ -0,0 +1,4 @@ +/* + Appellation: iter + Contrib: FL03 +*/ diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs new file mode 100644 index 0000000..56489c9 --- /dev/null +++ b/core/src/tape/mod.rs @@ -0,0 +1,33 @@ +/* + Appellation: tape + Contrib: FL03 +*/ +//! # Tape +//! +//! Idealized Turing machines consider a tape, or memory, that is infinite in both directions. +//! This tape is a one-dimensional array of symbols manipulated by the tape head according to +//! some set of pre-defined rules. +pub use self::tape::StdTape; + +pub(crate) mod tape; + +#[doc(hidden)] +pub mod entry; +#[doc(hidden)] +pub mod iter; +#[doc(hidden)] +pub mod slider; + +pub(crate) mod prelude { + pub use super::tape::StdTape; +} + +#[doc(hidden)] +pub trait RawTape { + type Elem; + + fn as_slice(&self) -> &[Self::Elem]; +} + +#[doc(hidden)] +pub trait Tape {} diff --git a/core/src/tape/slider.rs b/core/src/tape/slider.rs new file mode 100644 index 0000000..341e7eb --- /dev/null +++ b/core/src/tape/slider.rs @@ -0,0 +1,44 @@ +/* + Appellation: slider + Contrib: FL03 +*/ +#![allow(dead_code)] +use crate::State; + +/// +/// +/// In the paper, ["On the topological dynamics of Turing Machines"](https://pdf.sciencedirectassets.com/271538/1-s2.0-S0304397500X00527/1-s2.0-S0304397596000254/main.pdf?X-Amz-Security-Token=IQoJb3JpZ2luX2VjEC4aCXVzLWVhc3QtMSJHMEUCIAs%2FIGbrXGO61g5aPm39Ib9mhu0rk0voDj%2FUKAD%2B0EmVAiEAtagmY%2FVIBX8CvMgEmXsSzaOck0zIZmmoLxZ5eicB7nwqsgUIFxAFGgwwNTkwMDM1NDY4NjUiDDYtSMTlhppTdI2XOiqPBQ0lXDEHbefl0B8yi5yFePwQGNd18aDmyxP8Gglg%2FY5BIAPdXUNRIoe50cEbiKFm8HdtxVoszJGOBqN71165Tulos2iAdYmhGkzcqMJMikG%2FpAfZu1x3uo3frEbNtIW2J%2FSYo0vrK2OXh3LXb4VQkoZpceVDrG26ZgZWIuUXuSomzBkxy%2BfqvaOeqNrKqN22mxQe59mJYQCgaDP0ev1zltb8ULFHKHv35%2FX98bXTIXXBp7IXMjHdXddO9jhHONGa6HbGazEBhpxy1xs3mADH1ErJ0JlWG0GZwrkz9VM9ap%2Bwnq9niYgYd1adWqeuep6POgA0SZtgAFFFGLtGeHTRx%2B8I%2BSSzzYXK4rrNjnsdJXMkK9fXPOsTZPbtafM5IVBCtCFIClrRx9AKe%2FpDGNGJ9um2Teh%2FgZdamXl0dLCHBmUxxXXf5cH7QBPV1YzOO%2FdsFxhvrST%2FW7BWDEeNV89UVAjJjRXD4gT64B1aujgX55UCgYRJKpi8r8Z7scMdywDUA8lTFxG8ckFy8VSJXP4XIUo76TdmRao2MiDo6a0S3QUvlXp9j01mB%2FLRF0%2Bj7HPOH6PI23YdvMI1U%2BnwYu9FgyfFt8gDO6a3JYDUYmco5K13YXn0BiJtO4bd8D9q2WyCYoHzog4fDPKLArmrEqbBXqcJ5E6SEz7OkQuVIm3eFmSMsU%2BmbXx8di%2FRWaCVpwht3okeVnsci%2F2IMBwCiZnoByJ9a3KD9xavV81n6h%2BAL8YD2tyR%2BqaZdgi%2Fx8eMS8H14cLJB6o8ZpiGmthUXT66emKAhZfhnTweLEuEavsZcMIMOuI%2B9FEC2dfeUWjdtm0VnrufqEID2%2BowOXodj65RLAiD2wKTLYyuVVApBRW%2FFw0wrp%2BZtQY6sQEvfJW%2BnFXtKiHbJusaao0u5Y3T6RDPxNbcZMt1A%2FkN6icm1%2BP32LwAQ2DLIxmT6SFpc1SxogGCfvggZtF%2BxERxIr9B3HpMNnfvvEh9NvD6NQQAqbINxzEoKIMXksRuc5wrnry1KmA51CtmfJ2TbJOlZ1KWI%2FIJW1gcoU0omdhntl3162JQQZFd9jIKQ07K2ojI8FXtcs3tAJQho5g4eM%2F7bCqvDb1Sgn0B77vPL8LEdKI%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240728T144819Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Credential=ASIAQ3PHCVTY2B4ENHUE%2F20240728%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=35f40e1e6e1411dc3690307138e19043edef6f667f5ac5bbf191e0178217abc5&hash=0864d2d44896ab80e9b8766f9dd8b8d7516f124c8f19c29db323f504115bb2ba&host=68042c943591013ac2b2430a89b270f6af2c76d8dfd086a07176afe7c76c2c61&pii=S0304397596000254&tid=spdf-68cb7082-4608-4105-848d-6c23a206e008&sid=920ea93d24f32844d618d475ca675f16e0cbgxrqa&type=client&tsoh=d3d3LnNjaWVuY2VkaXJlY3QuY29t&ua=17155c0606530e0553&rr=8aa5ab6279d016b8&cc=us) +/// the authors define the state of a Turing machine to be its configuration. This +/// configuration consists of the inner state of the head, the symbol it is reading, +/// and the contents of the tape. +pub struct Slider { + pub(crate) state: State, // inner state of head + pub(crate) symbol: usize, // index of symbol + pub(crate) tape: Vec, // tape +} + +impl Slider { + pub fn new(State(state): State, tape: impl IntoIterator) -> Self { + Self { + state: State(state), + symbol: 0, + tape: tape.into_iter().collect(), + } + } + + pub fn state(&self) -> State<&Q> { + self.state.to_ref() + } + + pub fn symbol(&self) -> usize { + self.symbol + } + + pub fn read(&self) -> &S { + &self.tape[self.symbol] + } + + pub fn write(&mut self, symbol: S) { + self.tape[self.symbol] = symbol; + } +} diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs new file mode 100644 index 0000000..d9af628 --- /dev/null +++ b/core/src/tape/tape.rs @@ -0,0 +1,286 @@ +/* + Appellation: tape + Contrib: FL03 +*/ +use crate::{Direction, Error, Head, State, Tail}; +use core::cell::Cell; + +/// [StdTape] is an implementation of the traditional tape described by Turing machines. +/// +/// The tape, often thought of as the memory of the machine, is a one-dimensional array +/// of symbols in-which the tape head can read and write symbols. Furthermore, the tape +/// is infinite in both directions, meaning that the tape head can move left or right. +/// While this setup is largely hypothetical, it is a useful abstraction for understanding +/// the capabilities of Turing machines. +/// +/// Here, the [StdTape] employs the use of a [Vec] to store symbols while leveraging a +/// [usize] to keep track of the current position of the tape head. Moreover, the tape +/// stores the number of steps or operations taken by the tape head in a [Cell]. +/// This is done to quantify the impact of operations whose directions are defined to +/// be [Direction::Stay]. Moving left and right within a linear space speaks directly +/// to a translation or shift in space, however, staying in place does not result in +/// any movement, shift, or translation within space. That being said, staying still +/// is an operation that does result in some change in-time. +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct StdTape { + cursor: usize, + store: Vec, + ticks: Cell, +} + +impl StdTape { + pub fn new() -> Self { + StdTape { + cursor: 0, + store: Vec::::new(), + ticks: Cell::default(), + } + } + /// Constructs a new tape from an iterator. + pub fn from_iter(iter: impl IntoIterator) -> Self { + StdTape { + cursor: 0, + store: Vec::from_iter(iter), + ticks: Cell::default(), + } + } + /// Constructs a new, empty tape with the specified capacity. + pub fn with_capacity(capacity: usize) -> Self { + StdTape { + cursor: 0, + store: Vec::::with_capacity(capacity), + ticks: Cell::default(), + } + } + /// Returns a raw pointer to the store. + pub fn as_ptr(&self) -> *const S { + self.store.as_ptr() + } + /// Returns a mutable raw pointer to the store. + pub fn as_mut_ptr(&mut self) -> *mut S { + self.store.as_mut_ptr() + } + /// Returns an owned reference to the store as a [slice](core::slice) + pub fn as_slice(&self) -> &[S] { + &self.store + } + /// Returns a mutable reference to the store as a [slice](core::slice) + pub fn as_mut_slice(&mut self) -> &mut [S] { + &mut self.store + } + /// Clears the tape, removing all elements. + pub fn clear(&mut self) { + self.store.clear(); + } + /// Returns the number of elements in the tape. + pub fn len(&self) -> usize { + self.store.len() + } + /// Checks if the tape is empty; returns `true` if the tape is empty, + /// `false` otherwise. + pub fn is_empty(&self) -> bool { + self.store.is_empty() + } + + pub fn iter(&self) -> core::slice::Iter { + self.store.iter() + } + + pub fn ticks(&self) -> usize { + self.ticks.get() + } + + pub fn to_string(&self) -> String + where + S: core::fmt::Display, + { + format!("step ({}): {}", self.ticks(), self) + } + + /// Returns the current position of the tape head; + pub fn position(&self) -> usize { + self.cursor + } + + /// Returns an owned reference to the current symbol on the tape + pub fn read(&self) -> Result<&S, Error> { + self.get(self.cursor) + .ok_or(Error::index_out_of_bounds(self.cursor, self.len())) + } + /// + pub fn write(&mut self, direction: Direction, symbol: S) { + self.write_symbol(symbol); + self.shift(direction); + self.on_update(); + } + + /// + fn write_symbol(&mut self, symbol: S) { + if self.cursor < self.store.len() { + self.store[self.cursor] = symbol; + } else { + self.store.push(symbol); + } + } + + fn shift(&mut self, direction: Direction) -> usize { + self.on_update(); + self.cursor = direction.apply(self.cursor); + self.position() + } + + pub fn update(self, direction: Direction, state: State, symbol: S) -> (Self, Head) + where + S: Clone, + { + let head = Head::new(state, symbol.clone()); + let mut tape = self; + tape.write(direction, symbol); + tape.shift(direction); + (tape, head) + } + + pub fn update_inplace(&mut self, tail: Tail) -> State { + let Tail { + direction, + state, + symbol, + } = tail; + + self.write(direction, symbol); + self.shift(direction); + state + } + + fn on_update(&self) { + self.ticks.set(self.ticks.get() + 1); + } + + /// Given an index, return a reference to the symbol at that index; + /// panics if the index is out of bounds. + pub fn get(&self, idx: I) -> Option<&I::Output> + where + I: core::slice::SliceIndex<[S]>, + { + self.store.get(idx) + } + /// Removes and returns the last element of the tape, or `None` if it is empty. + pub fn pop(&mut self) -> Option { + self.store.pop() + } + /// Appends the given element to the back of the collection. + pub fn push(&mut self, symbol: S) { + self.store.push(symbol); + } +} + +impl StdTape { + pub fn from_str(input: &str) -> StdTape { + StdTape { + cursor: 0, + store: input.chars().collect(), + ticks: Cell::default(), + } + } +} + +impl AsRef<[S]> for StdTape { + fn as_ref(&self) -> &[S] { + &self.store + } +} + +impl AsMut<[S]> for StdTape { + fn as_mut(&mut self) -> &mut [S] { + &mut self.store + } +} + +impl core::borrow::Borrow<[S]> for StdTape { + fn borrow(&self) -> &[S] { + &self.store + } +} + +impl core::borrow::BorrowMut<[S]> for StdTape { + fn borrow_mut(&mut self) -> &mut [S] { + &mut self.store + } +} + +impl core::ops::Deref for StdTape { + type Target = [S]; + + fn deref(&self) -> &Self::Target { + &self.store + } +} + +impl core::ops::DerefMut for StdTape { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.store + } +} + +impl core::fmt::Display for StdTape +where + S: core::fmt::Display, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + for (i, c) in self.store.iter().enumerate() { + match c { + b if i == self.cursor => write!(f, "[{b}]")?, + _ => write!(f, "{c}")?, + } + } + Ok(()) + } +} + +impl core::iter::Extend for StdTape { + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + self.store.extend(iter); + } +} + +impl core::iter::FromIterator for StdTape { + fn from_iter(iter: I) -> Self + where + I: IntoIterator, + { + StdTape::from_iter(iter) + } +} + +impl core::iter::IntoIterator for StdTape { + type Item = S; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.store.into_iter() + } +} + +impl core::ops::Index for StdTape +where + I: core::slice::SliceIndex<[S]>, +{ + type Output = I::Output; + + fn index(&self, index: I) -> &Self::Output { + &self.store[index] + } +} + +impl core::ops::IndexMut for StdTape +where + I: core::slice::SliceIndex<[S]>, +{ + fn index_mut(&mut self, index: I) -> &mut Self::Output { + &mut self.store[index] + } +} diff --git a/core/src/traits/actor.rs b/core/src/traits/actor.rs new file mode 100644 index 0000000..879b201 --- /dev/null +++ b/core/src/traits/actor.rs @@ -0,0 +1,18 @@ +/* + Appellation: fsm + Contrib: FL03 +*/ + +pub trait Automata { + type Rule; + type State; + type Symbol; + + fn current_state(&self) -> Self::State; +} + +pub enum Step { + Left(T), + Right(T), + Stay(T), +} diff --git a/core/src/traits/io.rs b/core/src/traits/io.rs new file mode 100644 index 0000000..d04a1f6 --- /dev/null +++ b/core/src/traits/io.rs @@ -0,0 +1,57 @@ +/* + Appellation: io + Contrib: FL03 +*/ + +pub trait RawBuf { + type Elem; + + fn as_slice(&self) -> &[Self::Elem]; + fn as_mut_slice(&mut self) -> &mut [Self::Elem]; +} + +/// The `Read` trait provides a way to read bytes from a source +pub trait Read +where + B: RawBuf, +{ + type Output; + + fn read(&mut self, buf: &mut B) -> Self::Output; +} + +pub trait Write +where + B: RawBuf, +{ + type Output; + + fn write(&mut self, buf: &mut B) -> Self::Output; +} + +/* + ************* Implementations ************* +*/ +impl RawBuf for [T] { + type Elem = T; + + fn as_slice(&self) -> &[Self::Elem] { + self + } + + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self + } +} + +impl RawBuf for Vec { + type Elem = T; + + fn as_slice(&self) -> &[Self::Elem] { + self + } + + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self + } +} diff --git a/rstm/src/traits/mod.rs b/core/src/traits/mod.rs similarity index 69% rename from rstm/src/traits/mod.rs rename to core/src/traits/mod.rs index 0ad9e1a..1042dc1 100644 --- a/rstm/src/traits/mod.rs +++ b/core/src/traits/mod.rs @@ -3,14 +3,15 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::symbolic::Symbolic; +pub use self::symbolic::*; #[doc(hidden)] -pub mod fsm; +pub mod actor; #[doc(hidden)] -pub mod stateful; +pub mod io; pub mod symbolic; pub(crate) mod prelude { pub use super::symbolic::*; + // pub use super::transform::*; } diff --git a/core/src/traits/symbolic.rs b/core/src/traits/symbolic.rs new file mode 100644 index 0000000..2102db5 --- /dev/null +++ b/core/src/traits/symbolic.rs @@ -0,0 +1,74 @@ +/* + Appellation: symbolic + Contrib: FL03 +*/ + +/// [Alphabet] abstractly describes the set of symbols used for both +/// the input and output of any given Turing machine. +/// +/// ### Definition +/// +/// An alphabet is formally defines to be a finite set of symbols. +/// +/// Ideally, the alphabet should be implemented on unit enums since +/// each symbol can be represented as a unique variant and assigned +/// a particular value. The values of the variants may then be used +/// as pointers, specifiying the location of the symbol w.r.t. the +/// alphabet. +pub trait Alphabet: IntoIterator { + type Sym; + + fn len(&self) -> usize { + self.to_vec().len() + } + + fn to_vec(&self) -> Vec; +} + +/// [Symbolic] is a generic trait automatically implemented for any +/// type that satisfies the following conditions: +/// - Clone +/// - Eq +/// - Ord +pub trait Symbolic +where + Self: Clone + + Eq + + Ord + + PartialEq + + PartialOrd + + core::fmt::Debug + + core::fmt::Display + + core::hash::Hash, +{ +} + +#[doc(hidden)] +pub trait Symbol: Symbolic { + type Z; + + fn symbol(&self) -> char; + + fn is_symbol(&self, symbol: char) -> bool { + self.symbol() == symbol + } + /// Returns the value assigned to the symbol; + fn value(&self) -> Self::Z; +} + +/* + ************* Implementations ************* +*/ + +impl Alphabet for Vec { + type Sym = char; + + fn to_vec(&self) -> Vec { + self.clone() + } +} + +impl Symbolic for S where + S: Clone + Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash +{ +} diff --git a/core/src/types/direction.rs b/core/src/types/direction.rs new file mode 100644 index 0000000..03ca96e --- /dev/null +++ b/core/src/types/direction.rs @@ -0,0 +1,214 @@ +/* + Appellation: direction + Contrib: FL03 +*/ +/// The [AsDirection] trait provides a convience method for converting a type into a [Direction]. +pub trait AsDirection { + fn as_direction(&self) -> Direction; +} +/// The [IntoDirection] trait provides a convience method for converting a type into a [Direction]. +pub trait IntoDirection { + fn into_direction(self) -> Direction; +} + +/// [Direction] enumerates the various directions a head can move, namely: left, right, and stay. +/// The included methods and implementations aim to streamline the conversion between [Direction] and other types. +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + strum::AsRefStr, + strum::Display, + strum::EnumCount, + strum::EnumIter, + strum::VariantNames, +)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[repr(i8)] +#[strum(serialize_all = "lowercase")] +pub enum Direction { + #[cfg_attr( + feature = "serde", + serde( + alias = "left", + alias = "l", + alias = "L", + alias = "LEFT", + alias = "Left" + ) + )] + Left = -1, + #[cfg_attr( + feature = "serde", + serde( + alias = "right", + alias = "r", + alias = "R", + alias = "RIGHT", + alias = "Right" + ) + )] + Right = 1, + #[default] + #[cfg_attr( + feature = "serde", + serde( + alias = "stay", + alias = "s", + alias = "S", + alias = "STAY", + alias = "Stay" + ) + )] + Stay = 0, +} + +/* + ************* Implementations ************* +*/ +impl Direction { + /// A functional constructor for [Direction::Left]. + pub fn left() -> Self { + Self::Left + } + /// A functional constructor for [Direction::Right]. + pub fn right() -> Self { + Self::Right + } + /// A functional constructor for [Direction::Stay]. + pub fn stay() -> Self { + Self::Stay + } + /// Applies the shift to the given position in the [direction](Direction) specified by the current instance. + pub fn apply(&self, cur: usize) -> usize { + match self { + Self::Left => cur - 1, + Self::Right => cur + 1, + Self::Stay => cur, + } + } + /// Converts an [i8] value into a [`Direction`] by taking the modulus of the value. + /// The function uses a modulator of 2 to determine the direction since there are + /// only two actionable directions ([left](Direction::Left) and [right](Direction::Right)). + pub fn from_i8(value: i8) -> Self { + match value % 2 { + -1 => Self::Left, + 1 => Self::Right, + _ => Self::Stay, + } + } + /// Converts a [char] value into a direction; matches the value to the corresponding [direction](Direction). + pub fn from_char(value: char) -> Self { + match value { + 'L' | 'l' => Self::Left, + 'R' | 'r' => Self::Right, + _ => Self::Stay, + } + } + /// Returns a [char] representation of the [direction](Direction). + pub fn as_char(&self) -> char { + (*self).into_char() + } + + pub fn as_str(&self) -> &str { + (*self).as_ref() + } + /// Consumes the instance, returning a [char] representation of the [direction](Direction). + pub fn into_char(self) -> char { + match self { + Self::Left => 'L', + Self::Right => 'R', + Self::Stay => 'S', + } + } +} + +impl AsDirection for T +where + T: Clone + Into, +{ + fn as_direction(&self) -> Direction { + self.clone().into() + } +} + +impl IntoDirection for T +where + T: Into, +{ + fn into_direction(self) -> Direction { + self.into() + } +} + +mod impl_from { + use super::*; + + macro_rules! impl_from_direction { + ($($T:ident),*) => { + paste::paste! { + impl Direction { + $( + /// Converts an instance of the named type into a [Direction]. + pub fn [](value: $T) -> Self { + value.into_direction() + } + )* + } + } + $( + impl From<$T> for Direction { + fn from(value: $T) -> Self { + match value % 3 { + 0 => Self::Stay, + 1 => Self::Right, + _ => Self::Left, + } + } + } + )* + }; + (signed: $($T:ty),*) => { + $( + impl From<$T> for Direction { + fn from(value: $T) -> Self { + match value % 2 { + -1 => Self::Left, + 1 => Self::Right, + _ => Self::Stay, + } + } + } + )* + }; + } + + impl_from_direction!(u8, u16, u32, u64, u128, usize); + impl_from_direction!(signed: i8, i16, i32, i64, i128, isize); + + impl From for Direction { + fn from(value: char) -> Self { + match value { + 'L' | 'l' => Self::Left, + 'R' | 'r' => Self::Right, + _ => Self::Stay, + } + } + } + + impl From<&str> for Direction { + fn from(value: &str) -> Self { + match value { + "left" | "Left" | "LEFT" | "l" | "L" => Self::Left, + "right" | "Right" | "RIGHT" | "r" | "R" => Self::Right, + _ => Self::Stay, + } + } + } +} diff --git a/core/src/types/mod.rs b/core/src/types/mod.rs new file mode 100644 index 0000000..12139cb --- /dev/null +++ b/core/src/types/mod.rs @@ -0,0 +1,18 @@ +/* + Appellation: types + Contrib: FL03 +*/ +#[doc(inline)] +pub use self::direction::Direction; + +pub mod direction; + +pub(crate) mod prelude { + pub use super::direction::Direction; + + #[allow(unused)] + pub(crate) use super::Idx; +} + +/// A type alias generally used to represent the position of a value within a collection. +pub(crate) type Idx = usize; diff --git a/core/tests/default.rs b/core/tests/default.rs new file mode 100644 index 0000000..233a07a --- /dev/null +++ b/core/tests/default.rs @@ -0,0 +1,17 @@ +/* + Appellation: default + Contrib: FL03 +*/ + +fn add(a: A, b: B) -> C +where + A: core::ops::Add, +{ + a + b +} + +#[test] +fn compiles() { + assert_eq!(add(10, 10), 20); + assert_ne!(add(1, 1), 3); +} diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index f50ff32..68d92b4 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -21,17 +21,19 @@ full = [ "tracing", ] -# [FF] Dependencies +# ********* [FF] Dependencies ********* # alloc = [ # "serde?/alloc", # ] serde = [ "dep:serde", + "rstm-core/serde", ] tracing = [ "dep:tracing", + "rstm-core/tracing", ] # ********* [FF] Environments ********* @@ -51,12 +53,17 @@ test = true name = "basic" required-features = ["tracing"] +[[example]] +name = "utm" +required-features = ["tracing"] + +# ****************** Dependencies ****************** [dependencies] -thiserror = "1" +thiserror.workspace = true -[dev-dependencies] -lazy_static = "1" -tracing-subscriber = { features = [], version = "0.3" } +[dependencies.rstm-core] +path = "../core" +version = "0.0.2" [dependencies.serde] # default-features = false @@ -74,6 +81,11 @@ features = [] optional = true version = "0.1" +# ****************** Dev Dependencies ****************** +[dev-dependencies] +lazy_static.workspace = true +tracing-subscriber = { features = [], version = "0.3" } + [package.metadata.docs.rs] all-features = true rustc-args = ["--cfg", "docsrs"] diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 5f9ecb7..1bc296a 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -4,25 +4,28 @@ */ extern crate rstm; -use rstm::prelude::{State, Tape, TM}; -use rstm::rule; -use rstm::state::binary::BinaryStates::*; +use rstm::{ + rule, + state::{self, State}, + StdTape, TM, +}; -// use Direction::Right; +use state::BinState::*; fn main() -> Result<(), Box> { - tracing_subscriber::fmt().init(); - let tape = Tape::from_str("10111000101001101011010010"); - let initial_state = State(Invalid); + tracing_subscriber::fmt().with_target(false).init(); + println!("{}", -1_isize as u8); + let tape_data: Vec = vec![0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; let rules = vec![ - rule![(State(Invalid), '0') -> Right(State(Invalid), '1',)], - rule![(State(Invalid), '1') -> Right(State(Valid), '0',)], - rule![(State(Valid), '0') -> Right(State(Valid), '1',)], - rule![(State(Valid), '1') -> Right(State(Valid), '0',)], + rule![(Invalid, 0) -> Left(Invalid, 0)], + rule![(Invalid, 1) -> Right(Valid, 0)], + rule![(Valid, 0) -> Right(Valid, 1)], + rule![(Valid, 1) -> Left(Valid, 0)], ]; - let tm = TM::new(initial_state, rules, tape); + let tape = StdTape::from_iter(tape_data); + let tm = TM::new(State(Invalid), rules, tape); tm.run()?; Ok(()) } diff --git a/rstm/examples/utm.rs b/rstm/examples/utm.rs new file mode 100644 index 0000000..a176e96 --- /dev/null +++ b/rstm/examples/utm.rs @@ -0,0 +1,84 @@ +/* + Appellation: wolfram + Contrib: FL03 +*/ +extern crate rstm; + +use rstm::{ + rule, + state::{self, State}, + StdTape, TM, +}; + +use state::BinState::*; + +fn main() -> Result<(), Box> { + tracing_subscriber::fmt().with_level(true).init(); + tracing::info!("Example: Wolfram [2, 3] UTM"); + + let tape = StdTape::::from_iter([0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]); + let initial_state = State(Invalid); + + let rules = vec![ + rule![(Invalid, 0) -> Right(Invalid, 0)], + rule![(Invalid, 1) -> Right(Valid, 0)], + rule![(Valid, 0) -> Right(Valid, 1)], + rule![(Valid, 1) -> Right(Valid, 0)], + ]; + + let tm = TM::new(initial_state, rules, tape); + tm.run()?; + Ok(()) +} + +pub mod wolfram { + + #[derive( + Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, strum::EnumIter, + )] + #[repr(u8)] + pub enum Three { + #[default] + A = 0, + B = 1, + C = 2, + } + + impl Three { + pub fn as_u8(&self) -> u8 { + *self as u8 + } + + pub fn iter() -> impl Iterator { + use Three::*; + [A, B, C].into_iter() + } + + pub fn iter_value() -> impl Iterator { + [0, 1, 2].into_iter() + } + } + + impl rstm::Alphabet for Three { + type Sym = Self; + + fn to_vec(&self) -> Vec { + use Three::*; + vec![A, B, C] + } + } + + impl IntoIterator for Three { + type Item = Self; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + vec![Three::A, Three::B, Three::C].into_iter() + } + } + + pub enum Two { + A(T), + B(T), + } +} diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index 9dab738..aa74352 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -4,31 +4,27 @@ */ //! # rstm //! - +#![crate_name = "rstm"] // #![cfg_attr(not(feature = "std"), no_std)] // #[cfg(feature = "alloc")] // extern crate alloc; +pub use rstm_core::*; + #[doc(inline)] -pub use self::{error::FsmError, state::State, traits::prelude::*, turing::TM, types::prelude::*}; +pub use self::turing::TM; #[macro_use] -pub(crate) mod macros; -#[macro_use] -pub(crate) mod seal; +pub(crate) mod macros { + #[macro_use] + pub mod rules; +} -pub mod error; -pub mod rules; -pub mod state; -pub mod traits; +#[doc(hidden)] +pub mod sand; pub mod turing; -pub mod types; pub mod prelude { - pub use crate::error::FsmError; - pub use crate::rules::prelude::*; - pub use crate::state::prelude::*; - pub use crate::traits::prelude::*; pub use crate::turing::prelude::*; - pub use crate::types::prelude::*; + pub use rstm_core::prelude::*; } diff --git a/rstm/src/macros.rs b/rstm/src/macros.rs deleted file mode 100644 index 12225e2..0000000 --- a/rstm/src/macros.rs +++ /dev/null @@ -1,24 +0,0 @@ -/* - Appellation: macros - Contrib: FL03 -*/ - -#[macro_export] -macro_rules! rule { - [($state:expr, $symbol:literal $(,)?) -> $direction:ident($next:expr, $write:literal $(,)?) $(,)?] => { - $crate::rules::Instruction::new() - .state($state) - .symbol($symbol) - .write_symbol($write) - .direction($crate::Direction::$direction) - .next_state($next) - .build() - }; -} - -#[macro_export] -macro_rules! ruleset { - ($($($rule:tt)*);* $(,)?) => { - vec![$(rule!($($rule)*)),*] - }; -} diff --git a/rstm/src/macros/rules.rs b/rstm/src/macros/rules.rs new file mode 100644 index 0000000..598dedf --- /dev/null +++ b/rstm/src/macros/rules.rs @@ -0,0 +1,25 @@ +/* + Appellation: rules + Contrib: FL03 +*/ +/// A macro for creating. +/// +/// # Example +/// +/// ``` +/// +/// use rstm::rule; +/// +/// let rule = rule![(0, '0') -> Right(1, '1')]; +#[macro_export] +macro_rules! rule { + [($state:expr, $symbol:literal $(,)?) -> $direction:ident($next:expr, $write:literal $(,)?) $(,)?] => { + rstm_core::Instruction::new() + .state(rstm_core::State($state)) + .symbol($symbol) + .write_symbol($write) + .direction(rstm_core::Direction::$direction) + .next_state(rstm_core::State($next)) + .build() + }; +} diff --git a/rstm/src/rules/mod.rs b/rstm/src/rules/mod.rs deleted file mode 100644 index a4c5440..0000000 --- a/rstm/src/rules/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -/* - Appellation: programs - Contrib: FL03 -*/ -#[doc(inline)] -pub use self::{instruction::*, program::*}; - -pub(crate) mod instruction; -pub(crate) mod program; - -pub(crate) mod prelude { - pub use super::instruction::Instruction; - pub use super::program::Program; -} diff --git a/rstm/src/sand/mod.rs b/rstm/src/sand/mod.rs new file mode 100644 index 0000000..f224617 --- /dev/null +++ b/rstm/src/sand/mod.rs @@ -0,0 +1,7 @@ +/* + Appellation: sand + Contrib: FL03 +*/ +#![allow(unused)] + +pub mod types; diff --git a/rstm/src/sand/types/mod.rs b/rstm/src/sand/types/mod.rs new file mode 100644 index 0000000..2134f89 --- /dev/null +++ b/rstm/src/sand/types/mod.rs @@ -0,0 +1,16 @@ +/* + Appellation: types + Contrib: FL03 +*/ + +pub mod registry; +pub mod scope; +pub mod store; + +pub(crate) mod prelude { + + pub(crate) use super::Idx; +} + +/// A type alias generally used to represent the position of a value within a collection. +pub(crate) type Idx = usize; diff --git a/rstm/src/sand/types/registry.rs b/rstm/src/sand/types/registry.rs new file mode 100644 index 0000000..fdc83e0 --- /dev/null +++ b/rstm/src/sand/types/registry.rs @@ -0,0 +1,17 @@ +/* + Appellation: registry + Contrib: FL03 +*/ +use crate::rules::Instruction; +use std::collections::hash_map::{self, HashMap}; + +type Store = HashMap>; + +pub struct Registry { + pub(crate) rules: HashMap>, +} + +pub struct Actor { + pub(crate) pos: isize, // + pub(crate) rule: Instruction, +} diff --git a/rstm/src/types/scope.rs b/rstm/src/sand/types/scope.rs similarity index 100% rename from rstm/src/types/scope.rs rename to rstm/src/sand/types/scope.rs diff --git a/rstm/src/sand/types/store.rs b/rstm/src/sand/types/store.rs new file mode 100644 index 0000000..b1eea15 --- /dev/null +++ b/rstm/src/sand/types/store.rs @@ -0,0 +1,128 @@ +/* + Appellation: symbol + Contrib: FL03 +*/ +use crate::{Head, Symbolic, Tail}; +use std::collections::hash_map::{self, Entry, HashMap}; + +pub struct Ruleset { + pub(crate) rules: HashMap, Tail>, +} + +impl Ruleset +where + Q: Eq + core::hash::Hash, + S: Symbolic, +{ + pub fn new() -> Self { + Ruleset { + rules: HashMap::new(), + } + } + pub fn from_iter(iter: I) -> Self + where + I: IntoIterator, + R: Into<(Head, Tail)>, + HashMap, Tail>: FromIterator, + { + Ruleset { + rules: iter.into_iter().collect(), + } + } + pub fn from_rules(rules: HashMap, Tail>) -> Self { + Ruleset { rules } + } + /// Given a head, returns an [entry](Entry) in the ruleset for in-place manipulation + pub fn entry(&mut self, key: Head) -> Entry<'_, Head, Tail> { + self.rules.entry(key) + } + /// Inserts a new rule into the ruleset + pub fn insert(&mut self, head: Head, tail: Tail) { + self.rules.insert(head, tail); + } + /// Returns a reference to the tail of a given head; + /// if the head is not in the ruleset, returns [None](Option::None) + pub fn get(&self, head: &Head) -> Option<&Tail> { + self.rules.get(head) + } + /// Returns a mutable reference to the tail of a given head; + /// if the head is not in the ruleset, returns [None](Option::None) + pub fn get_mut(&mut self, head: &Head) -> Option<&mut Tail> { + self.rules.get_mut(head) + } + /// Returns the number of rules in the ruleset + pub fn len(&self) -> usize { + self.rules.len() + } + /// Check to see whether the ruleset is empty + pub fn is_empty(&self) -> bool { + self.rules.is_empty() + } + + pub fn iter(&self) -> hash_map::Iter<'_, Head, Tail> { + self.rules.iter() + } + + pub fn iter_mut(&mut self) -> hash_map::IterMut<'_, Head, Tail> { + self.rules.iter_mut() + } + + pub fn keys(&self) -> hash_map::Keys<'_, Head, Tail> { + self.rules.keys() + } + + pub fn values(&self) -> hash_map::Values<'_, Head, Tail> { + self.rules.values() + } + + pub fn values_mut(&mut self) -> hash_map::ValuesMut<'_, Head, Tail> { + self.rules.values_mut() + } + + pub fn retain(&mut self, f: F) + where + F: FnMut(&Head, &mut Tail) -> bool, + { + self.rules.retain(f) + } + + pub fn remove(&mut self, head: &Head) -> Option> { + self.rules.remove(head) + } +} + +impl Extend<(Head, Tail)> for Ruleset +where + Q: Eq + core::hash::Hash, + S: Symbolic, +{ + fn extend(&mut self, iter: T) + where + T: IntoIterator, Tail)>, + { + self.rules.extend(iter) + } +} + +impl Extend> for Ruleset +where + Q: Eq + core::hash::Hash, + S: Symbolic, +{ + fn extend(&mut self, iter: T) + where + T: IntoIterator>, + { + self.rules + .extend(iter.into_iter().map(|i| (i.head, i.tail))) + } +} + +impl IntoIterator for Ruleset { + type Item = (Head, Tail); + type IntoIter = hash_map::IntoIter, Tail>; + + fn into_iter(self) -> Self::IntoIter { + self.rules.into_iter() + } +} diff --git a/rstm/src/state/mod.rs b/rstm/src/state/mod.rs deleted file mode 100644 index 55d01c6..0000000 --- a/rstm/src/state/mod.rs +++ /dev/null @@ -1,56 +0,0 @@ -/* - Appellation: state - Contrib: FL03 -*/ -#[doc(inline)] -pub use self::{state::State, states::*}; - -pub(crate) mod state; - -pub(crate) mod states { - #[doc(inline)] - pub use self::binary::BinaryState; - - pub mod binary; - pub mod halting; - - pub(crate) mod prelude { - pub use super::binary::*; - } -} - -pub(crate) mod prelude { - - pub use super::state::State; - pub use super::states::prelude::*; -} - -/// -pub trait Haltable { - fn halt(&self) -> bool; -} - -impl Haltable for bool { - fn halt(&self) -> bool { - *self - } -} - -impl Haltable for char { - fn halt(&self) -> bool { - *self == 'H' - } -} - -impl Haltable for String { - fn halt(&self) -> bool { - self.as_str().halt() - } -} - -impl Haltable for &str { - fn halt(&self) -> bool { - let s = self.to_string().to_lowercase(); - matches!(s.as_str(), "h" | "H" | "stop" | "terminate") - } -} diff --git a/rstm/src/state/state.rs b/rstm/src/state/state.rs deleted file mode 100644 index a6c3475..0000000 --- a/rstm/src/state/state.rs +++ /dev/null @@ -1,174 +0,0 @@ -/* - Appellation: state - Contrib: FL03 -*/ - -#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[repr(transparent)] -pub struct State(pub Q); - -impl State { - pub fn new(state: Q) -> Self { - Self(state) - } - - pub fn into_inner(self) -> Q { - self.0 - } - - pub fn as_ref(&self) -> &Q { - &self.0 - } - - pub fn as_mut(&mut self) -> &mut Q { - &mut self.0 - } -} - -impl State { - pub fn is_halt(&self) -> bool { - self.0 == 'H' || self.0 == 'h' - } -} - -impl State<&str> { - pub fn is_halt(&self) -> bool { - self.0.to_lowercase() == "halt" - } -} - -impl State { - pub fn is_halt(&self) -> bool { - self.0.to_lowercase() == "halt" - } -} - -impl AsRef for State { - fn as_ref(&self) -> &Q { - &self.0 - } -} - -impl AsMut for State { - fn as_mut(&mut self) -> &mut Q { - &mut self.0 - } -} - -impl core::borrow::Borrow for State { - fn borrow(&self) -> &Q { - &self.0 - } -} - -impl core::borrow::BorrowMut for State { - fn borrow_mut(&mut self) -> &mut Q { - &mut self.0 - } -} - -impl core::ops::Deref for State { - type Target = Q; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl core::ops::DerefMut for State { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl core::fmt::Binary for State -where - Q: core::fmt::Binary, -{ - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{:b}", self.0) - } -} - -impl core::fmt::Display for State -where - Q: core::fmt::Display, -{ - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl core::fmt::LowerExp for State -where - Q: core::fmt::LowerExp, -{ - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{:e}", self.0) - } -} - -impl core::fmt::LowerHex for State -where - Q: core::fmt::LowerHex, -{ - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{:x}", self.0) - } -} - -impl core::fmt::Octal for State -where - Q: core::fmt::Octal, -{ - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{:o}", self.0) - } -} - -impl core::fmt::UpperExp for State -where - Q: core::fmt::UpperExp, -{ - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{:E}", self.0) - } -} - -impl core::fmt::UpperHex for State -where - Q: core::fmt::UpperHex, -{ - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{:X}", self.0) - } -} - -unsafe impl core::marker::Send for State where Q: core::marker::Send {} - -unsafe impl core::marker::Sync for State where Q: core::marker::Sync {} - -impl core::cmp::PartialEq for State -where - Q: core::cmp::PartialEq, -{ - fn eq(&self, other: &Q) -> bool { - self.0 == *other - } -} - -impl core::cmp::PartialOrd for State -where - Q: core::cmp::PartialOrd, -{ - fn partial_cmp(&self, other: &Q) -> Option { - self.0.partial_cmp(other) - } -} - -impl From for State { - fn from(state: Q) -> Self { - Self(state) - } -} diff --git a/rstm/src/state/states/halting.rs b/rstm/src/state/states/halting.rs deleted file mode 100644 index 245d636..0000000 --- a/rstm/src/state/states/halting.rs +++ /dev/null @@ -1,10 +0,0 @@ -/* - Appellation: halting - Contrib: FL03 -*/ - -pub trait PowerMode { - private!(); -} - -pub enum On {} diff --git a/rstm/src/traits/fsm.rs b/rstm/src/traits/fsm.rs deleted file mode 100644 index ef96a06..0000000 --- a/rstm/src/traits/fsm.rs +++ /dev/null @@ -1,9 +0,0 @@ -/* - Appellation: fsm - Contrib: FL03 -*/ - -// pub trait Rule { -// type -// type State; -// } diff --git a/rstm/src/traits/stateful.rs b/rstm/src/traits/stateful.rs deleted file mode 100644 index 5f6ec4b..0000000 --- a/rstm/src/traits/stateful.rs +++ /dev/null @@ -1,46 +0,0 @@ -/* - Appellation: stateful - Contrib: FL03 -*/ - -/// S -pub trait BaseState { - type Data; - - fn data(&self) -> &Self::Data; - - fn data_mut(&mut self) -> &mut Self::Data; - - #[doc(hidden)] - fn swap(&mut self, state: S::Data) -> S - where - S: BaseState; -} - -/// [Stateful] is used to describe objects which rely upon a state. -/// -pub trait Stateful { - type State: BaseState; -} - -#[allow(unused)] -#[doc(hidden)] -mod private { - use super::BaseState; - - pub enum TimePerspective { - Past(T), - Present(T), - Future(T), - } - - pub enum StateGroup - where - S: BaseState, - { - A { prev: S, curr: S }, - B { curr: S, next: S }, - C { prev: S, next: S }, - D { prev: S, curr: S, next: S }, - } -} diff --git a/rstm/src/traits/symbolic.rs b/rstm/src/traits/symbolic.rs deleted file mode 100644 index 660eeb8..0000000 --- a/rstm/src/traits/symbolic.rs +++ /dev/null @@ -1,58 +0,0 @@ -/* - Appellation: symbolic - Contrib: FL03 -*/ - -pub trait Alphabet { - type Elem; - - fn symbols(&self) -> Vec; -} - -pub trait AsRefChar { - fn as_char(&self) -> &char; -} - -pub trait Symbol { - fn as_ptr(&self) -> *const char; - - fn symbol(&self) -> char; -} - -pub trait Symbolic: Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash {} - -/* - ************* Implementations ************* -*/ - -impl AsRefChar for T -where - T: AsRef, -{ - fn as_char(&self) -> &char { - self.as_ref() - } -} - -impl Alphabet for Vec { - type Elem = char; - - fn symbols(&self) -> Vec { - self.clone() - } -} - -impl Symbol for char { - fn as_ptr(&self) -> *const char { - self as *const char - } - - fn symbol(&self) -> char { - *self - } -} - -impl Symbolic for S where - S: Symbol + Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash -{ -} diff --git a/rstm/src/turing/actor.rs b/rstm/src/turing/actor.rs deleted file mode 100644 index ba35c70..0000000 --- a/rstm/src/turing/actor.rs +++ /dev/null @@ -1,49 +0,0 @@ -/* - Appellation: actor - Contrib: FL03 -*/ -use crate::prelude::{Direction, Head, Tail}; -use crate::state::State; - -pub struct Actor { - pub(crate) head: Head, - pub(crate) tail: Tail, -} - -impl Actor { - pub fn new(head: Head, tail: Tail) -> Self { - Self { head, tail } - } - - pub const fn head(&self) -> &Head { - &self.head - } - - pub const fn tail(&self) -> &Tail { - &self.tail - } - - pub fn head_mut(&mut self) -> &mut Head { - &mut self.head - } - /// Returns a mutable reference to the tail of the agent - pub fn tail_mut(&mut self) -> &mut Tail { - &mut self.tail - } - /// Returns the current [state](State) the agent is in - pub fn current_state(&self) -> &State { - self.head.state() - } - /// Returns a copy of the [direction](Direction) the agent is instructed to move - pub fn direction(&self) -> Direction { - self.tail().direction() - } - /// Returns an immutable, owned reference to the next [state](State) - pub fn next_state(&self) -> &State { - self.tail().next_state() - } - /// Returns a copy of the symbol the agent is instructed to write - pub fn write_symbol(&self) -> char { - self.tail().symbol - } -} diff --git a/rstm/src/turing/context.rs b/rstm/src/turing/context.rs index ba3b67c..018b949 100644 --- a/rstm/src/turing/context.rs +++ b/rstm/src/turing/context.rs @@ -38,14 +38,15 @@ impl Context { } } - /// Returns the current state of the system; - /// if the state is [none](Option::None), assumes the initial state. - pub fn current_state(&self) -> &State { - self.state.as_ref().unwrap_or(self.initial_state()) - } - - pub const fn initial_state(&self) -> &State { - &self.program.initial_state() + // /// Returns the current state of the system; + // /// if the state is [none](Option::None), assumes the initial state. + // pub fn current_state(&self) -> State<&'_ Q> { + // let q = &self.state.map(State::into_inner).unwrap_or(self.program.initial_state.into_inner()); + // State(q) + // } + + pub fn initial_state(&self) -> State<&'_ Q> { + self.program.initial_state() } pub fn program(&self) -> &Program { diff --git a/rstm/src/turing/mod.rs b/rstm/src/turing/mod.rs index 99f0698..6981970 100644 --- a/rstm/src/turing/mod.rs +++ b/rstm/src/turing/mod.rs @@ -2,7 +2,7 @@ Appellation: turing Contrib: FL03 */ -//!## Turing Machine +//! # Turing Machine ([TM]) //! //! ### Overview //! @@ -11,9 +11,8 @@ //! across the tape. The machine uses a set of pre-defined rules to determine the next state and symbol. //! #[doc(inline)] -pub use self::{actor::Actor, context::Context, model::TM}; +pub use self::{context::Context, model::TM}; -pub(crate) mod actor; pub(crate) mod context; pub(crate) mod model; @@ -22,4 +21,15 @@ pub(crate) mod prelude { } #[doc(hidden)] -pub trait Turing {} +pub trait Turing { + type Alpha; // input alphabet + type Beta; // output alphabet + type Gamma; // +} + +pub trait Ctx {} +pub trait Actor { + type Ctx; + + fn handle(&self, context: Context) -> Result<(), Box>; +} diff --git a/rstm/src/turing/model.rs b/rstm/src/turing/model.rs index c3b5e42..da916ae 100644 --- a/rstm/src/turing/model.rs +++ b/rstm/src/turing/model.rs @@ -2,128 +2,126 @@ Appellation: tm Contrib: FL03 */ -use super::Context; - -use crate::prelude::{FsmError, Head, Symbolic, Tape}; +use crate::prelude::{Error, Head, StdTape, Symbolic}; use crate::rules::{Instruction, Program}; -use crate::state::{Haltable, State}; +use crate::state::State; /// # Turing Machine ([TM]) /// +/// The Turing Machine is a mathematical model of computation that uses a set of rules to determine +/// how a machine should manipulate a tape. The machine can read, write, and move linearly across the tape. +/// Each pre-defined rule maps a head, consisting of a state and symbol, to a new state and symbol along with a direction. #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct TM { - pub(crate) ctx: Context, - pub(crate) tape: Tape, + pub(crate) program: Program, + pub(crate) state: State, + pub(crate) tape: StdTape, } impl TM { pub fn new( - initial_state: State, + State(state): State, instructions: impl IntoIterator>, - tape: Tape, + tape: StdTape, ) -> Self where Q: Clone, S: Clone + Default, { - let program = Program::new(initial_state.clone()).with_instructions(instructions); - let ctx = Context::new(program, initial_state); - TM { ctx, tape } - } - - pub const fn context(&self) -> &Context { - &self.ctx - } - - pub fn current_state(&self) -> &State { - self.context().current_state() + let state = State(state); + let program = Program::new(state.clone()).with_instructions(instructions); + TM { + program, + state, + tape, + } } - - pub fn head(&self) -> Head + /// Creates a new instance of a [head](Head) from references to the current state and symbol; + pub fn head(&self) -> Head<&'_ Q, &'_ S> where Q: Clone, S: Clone, { - let state = self.current_state().clone(); - let symbol = self.tape.read().unwrap().clone(); + let state = self.state(); + let symbol = self.tape().read().unwrap(); Head::new(state, symbol) } - - pub const fn tape(&self) -> &Tape { + /// Returns an immutable reference to the [program](Program) + pub const fn program(&self) -> &Program { + &self.program + } + /// Returns an instance of the [state](State) with an immutable + /// reference to the internal data + pub fn state(&self) -> State<&'_ Q> { + self.state.to_ref() + } + /// Returns an instance of the [state](State) with a mutable + /// reference to the internal data + pub fn state_mut(&mut self) -> State<&'_ mut Q> { + self.state.to_mut() + } + /// Returns an instance of the [state](State) with an immutable + pub fn set_state(&mut self, state: State) { + self.state = state; + } + /// Returns an immutable reference to the [tape](StdTape) + pub const fn tape(&self) -> &StdTape { &self.tape } - - pub fn tape_mut(&mut self) -> &mut Tape { + /// Returns a mutable reference to the [tape](StdTape) + pub fn tape_mut(&mut self) -> &mut StdTape { &mut self.tape } -} - -// #[cfg(feature = "std")] -impl TM -where - Q: Clone + PartialEq, - S: Clone + Symbolic, -{ - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, name = "step", target = "fsm") - )] - pub fn step(&mut self) -> Result<(), FsmError> { - #[cfg(feature = "tracing")] - tracing::info!("Stepping..."); - let prog = self.ctx.program.clone(); - // Get a clone of the current state - let cst = self.current_state().clone(); - let sym = self.tape().read()?.clone(); - let head = Head::new(cst.clone(), sym); - if let Some(tail) = prog.get_head(&head).first().cloned() { - let nxt = self.tape.update_inplace(tail.clone()); - self.ctx.set_state(nxt); - return Ok(()); - } - Err(FsmError::state_not_found("")) - } + /// Runs the program until the + /// + /// The program will continue to run until the current state is a halt state. #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "run", target = "fsm") )] - pub fn run(mut self) -> Result<(), FsmError> { + pub fn run(mut self) -> Result<(), Error> where Q: Clone + PartialEq, S: Symbolic { #[cfg(feature = "tracing")] tracing::info!("Running the program..."); loop { #[cfg(feature = "tracing")] tracing::info!("{}", &self.tape); - match self.step() { - Ok(_) => continue, - Err(e) => { - return Err(e); + match self.next() { + Some(_) => { + // if self.current_state().is_halt() { + // return Ok(()); + // } + continue; + } + None => { + return Err(Error::unknown("Runtime Error")); } } } } } -impl TM +impl core::iter::Iterator for TM where - Q: Clone + Eq + core::hash::Hash + Haltable, + Q: Clone + PartialEq, + S: Symbolic, { - pub fn run_haltable(&mut self) -> Result<(), FsmError> { - let _ = loop { - dbg!(self.tape()); - match self.step() { - Ok(_) => (), - Err(e) => { - eprintln!("{}", e); - break; - } - } + type Item = Head; - if self.current_state().halt() { - break; - } - }; - - Ok(()) + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "step", target = "fsm") + )] + fn next(&mut self) -> Option { + #[cfg(feature = "tracing")] + tracing::info!("Stepping..."); + // Create a new head from the current state and symbol + let head = self.head().cloned(); + // Get the first instruction for the current head + if let Some(&tail) = self.program.get_head(&head).first() { + self.state = self.tape.update_inplace(tail.cloned()); + return Some(tail.cloned().into_head()); + } + None } } diff --git a/rstm/src/types/direction.rs b/rstm/src/types/direction.rs deleted file mode 100644 index effb003..0000000 --- a/rstm/src/types/direction.rs +++ /dev/null @@ -1,185 +0,0 @@ -/* - Appellation: direction - Contrib: FL03 -*/ - -pub trait IntoDirection { - fn into_direction(self) -> Direction; -} - -impl IntoDirection for i8 { - fn into_direction(self) -> Direction { - Direction::from(self) - } -} - -impl IntoDirection for char { - fn into_direction(self) -> Direction { - Direction::from(self) - } -} - -impl IntoDirection for &str { - fn into_direction(self) -> Direction { - Direction::from(self) - } -} - -/// [Direction] enumerates the various directions a head can move, namely: left, right, and stay. -/// The included methods and implementations aim to streamline the conversion between [Direction] and other types. -#[derive( - Clone, - Copy, - Debug, - Default, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - strum::AsRefStr, - strum::Display, - strum::EnumCount, - strum::EnumIter, - strum::VariantNames, -)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[repr(i8)] -#[strum(serialize_all = "lowercase")] -pub enum Direction { - #[cfg_attr( - feature = "serde", - serde( - alias = "left", - alias = "l", - alias = "L", - alias = "LEFT", - alias = "Left" - ) - )] - Left = -1, - #[cfg_attr( - feature = "serde", - serde( - alias = "right", - alias = "r", - alias = "R", - alias = "RIGHT", - alias = "Right" - ) - )] - Right = 1, - #[default] - #[cfg_attr( - feature = "serde", - serde( - alias = "stay", - alias = "s", - alias = "S", - alias = "STAY", - alias = "Stay" - ) - )] - Stay = 0, -} - -impl Direction { - /// A functional constructor for [Direction::Left]. - pub fn left() -> Self { - Self::Left - } - /// A functional constructor for [Direction::Right]. - pub fn right() -> Self { - Self::Right - } - /// A functional constructor for [Direction::Stay]. - pub fn stay() -> Self { - Self::Stay - } - - pub fn apply(&self, position: usize) -> usize { - match self { - Self::Left => position - 1, - Self::Right => position + 1, - Self::Stay => position, - } - } - /// Converts an [i8] value into a [Direction] by taking the modulus of the value. - /// The function uses a modulator of 2 to determine the direction since there are - /// only two actionable directions ([left](Direction::Left) and [right](Direction::Right)). - pub fn from_i8(value: i8) -> Self { - match value % 2 { - -1 => Self::Left, - 1 => Self::Right, - _ => Self::Stay, - } - } - /// Converts a [char] value into a direction; matches the value to the corresponding direction. - pub fn from_char(value: char) -> Self { - match value { - 'L' | 'l' => Self::Left, - 'R' | 'r' => Self::Right, - _ => Self::Stay, - } - } - - pub fn into_char(self) -> char { - match self { - Self::Left => 'L', - Self::Right => 'R', - Self::Stay => 'S', - } - } -} - -macro_rules! impl_from_direction { - ($($T:ty),*) => { - $( - impl From<$T> for Direction { - fn from(value: $T) -> Self { - match value % 3 { - 0 => Self::Stay, - 1 => Self::Right, - _ => Self::Left, - } - } - } - )* - }; - (signed: $($T:ty),*) => { - $( - impl From<$T> for Direction { - fn from(value: $T) -> Self { - match value % 2 { - -1 => Self::Left, - 1 => Self::Right, - _ => Self::Stay, - } - } - } - )* - }; -} - -impl_from_direction!(u8, u16, u32, u64, u128, usize); -impl_from_direction!(signed: i8, i16, i32, i64, i128, isize); - -impl From for Direction { - fn from(value: char) -> Self { - match value { - 'L' | 'l' => Self::Left, - 'R' | 'r' => Self::Right, - _ => Self::Stay, - } - } -} - -impl From<&str> for Direction { - fn from(value: &str) -> Self { - match value { - "left" | "Left" | "LEFT" | "l" | "L" => Self::Left, - "right" | "Right" | "RIGHT" | "r" | "R" => Self::Right, - _ => Self::Stay, - } - } -} diff --git a/rstm/src/types/mod.rs b/rstm/src/types/mod.rs deleted file mode 100644 index 9e822b9..0000000 --- a/rstm/src/types/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -/* - Appellation: types - Contrib: FL03 -*/ -#[doc(inline)] -pub use self::{direction::Direction, head::Head, tail::Tail, tape::Tape}; - -pub mod direction; -pub mod head; -#[doc(hidden)] -pub mod scope; -pub mod symbol; -pub mod tail; -pub mod tape; - -pub(crate) mod prelude { - pub use super::direction::Direction; - pub use super::head::Head; - pub use super::tail::Tail; - pub use super::tape::Tape; - pub use super::Registry; -} - -/// A registry of [head](Head) and [tail](Tail) pairs -pub type Registry = std::collections::HashMap, Tail>; diff --git a/rstm/src/types/symbol.rs b/rstm/src/types/symbol.rs deleted file mode 100644 index 43ab3d5..0000000 --- a/rstm/src/types/symbol.rs +++ /dev/null @@ -1,12 +0,0 @@ -/* - Appellation: symbol - Contrib: FL03 -*/ -use crate::Symbol; - -pub struct InputAlpha -where - S: Symbol, -{ - pub symbols: Vec, -} diff --git a/rstm/src/types/tail.rs b/rstm/src/types/tail.rs deleted file mode 100644 index ad23884..0000000 --- a/rstm/src/types/tail.rs +++ /dev/null @@ -1,43 +0,0 @@ -/* - Appellation: head - Contrib: FL03 -*/ -use crate::{Direction, State}; - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Tail { - pub(crate) direction: Direction, - pub(crate) state: State, - pub(crate) symbol: S, -} - -impl Tail { - pub fn new(direction: Direction, State(state): State, symbol: S) -> Self { - Self { - direction, - state: State(state), - symbol, - } - } - /// Returns the direction, state, and symbol as a 3-tuple - pub fn as_tuple(&self) -> (Direction, &State, &S) { - (self.direction, &self.state, &self.symbol) - } - /// Consumes the tail and returns the direction, state, and symbol as a 3-tuple - pub fn into_tuple(self) -> (Direction, State, S) { - (self.direction, self.state, self.symbol) - } - /// Returns the direction the [head](crate::Head) is instructed to move - pub fn direction(&self) -> Direction { - self.direction - } - /// Returns the next [state](State) the agent is instructed to move to - pub const fn next_state(&self) -> &State { - &self.state - } - /// Returns the [symbol](crate::Symbolic) the [head](crate::Head) is instructed to write - pub const fn write_symbol(&self) -> &S { - &self.symbol - } -} diff --git a/rstm/src/types/tape.rs b/rstm/src/types/tape.rs deleted file mode 100644 index 3c4ae28..0000000 --- a/rstm/src/types/tape.rs +++ /dev/null @@ -1,224 +0,0 @@ -/* - Appellation: tape - Contrib: FL03 -*/ -use crate::{Direction, FsmError, State, Tail}; -use core::cell::Cell; - -use super::Head; - -#[allow(unused)] -#[doc(hidden)] -pub struct Slider { - scope: usize, - state: *const State, -} - -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Tape { - pos: usize, - store: Vec, - ticks: Cell, -} - -impl Tape { - pub fn new() -> Self { - Tape { - pos: 0, - store: Vec::::new(), - ticks: Cell::default(), - } - } - /// Returns an owned reference to the store as a [slice](core::slice) - pub fn as_slice(&self) -> &[S] { - &self.store - } - /// Returns a mutable reference to the store as a [slice](core::slice) - pub fn as_mut_slice(&mut self) -> &mut [S] { - &mut self.store - } - /// Returns the number of elements in the tape. - pub fn len(&self) -> usize { - self.store.len() - } - /// Given an index, return a reference to the symbol at that index; - /// panics if the index is out of bounds. - pub fn get(&self, idx: I) -> Option<&I::Output> - where - I: core::slice::SliceIndex<[S]>, - { - self.store.get(idx) - } - - pub fn ticks(&self) -> usize { - self.ticks.get() - } - - pub fn to_string(&self) -> String - where - S: core::fmt::Display, - { - format!("step ({}): {}", self.ticks(), self) - } - /// Removes and returns the last element of the tape, or `None` if it is empty. - pub fn pop(&mut self) -> Option { - self.store.pop() - } - /// Returns the current position of the tape head; - pub fn position(&self) -> usize { - self.pos - } - /// Appends the given element to the back of the collection. - pub fn push(&mut self, symbol: S) { - self.store.push(symbol); - } - /// Returns an owned reference to the current symbol on the tape - pub fn read(&self) -> Result<&S, FsmError> { - self.get(self.pos) - .ok_or(FsmError::index_out_of_bounds(self.pos)) - } - /// - pub fn write(&mut self, symbol: S) { - if self.pos < self.store.len() { - self.store[self.pos] = symbol; - } else { - self.store.push(symbol); - } - } - - pub fn write_iter(&mut self, iter: impl Iterator) { - for (i, symbol) in iter.enumerate() { - if i < self.store.len() { - self.store[i] = symbol; - } else { - self.store.push(symbol); - } - } - } - - pub fn shift(self, direction: Direction) -> Self { - self.on_update(); - Self { - pos: direction.apply(self.pos), - store: self.store, - ticks: self.ticks, - } - } - - pub fn shift_left(self) -> Self { - self.shift(Direction::Left) - } - - pub fn shift_right(self) -> Self { - self.shift(Direction::Right) - } - - pub fn step(&mut self, direction: Direction) { - self.pos = direction.apply(self.pos); - self.on_update(); - } - - pub fn step_left(&mut self) { - self.step(Direction::Left); - } - - pub fn step_right(&mut self) { - self.step(Direction::Right); - } - - pub fn update(self, tail: Tail) -> (Self, Head) - where - S: Clone, - { - let Tail { - direction, - state, - symbol, - } = tail; - let mut tape = self; - tape.write(symbol.clone()); - tape.step(direction); - tape.on_update(); - (tape, Head::new(state, symbol)) - } - - pub fn update_inplace(&mut self, tail: Tail) -> State { - let Tail { - direction, - state, - symbol, - } = tail; - self.write(symbol); - self.step(direction); - self.on_update(); - state - } - - fn on_update(&self) { - self.ticks.set(self.ticks.get() + 1); - } -} - -impl Tape { - pub fn from_str(input: &str) -> Tape { - Tape { - pos: 0, - store: input.chars().collect(), - ticks: Cell::default(), - } - } -} - -impl AsRef<[S]> for Tape { - fn as_ref(&self) -> &[S] { - &self.store - } -} - -impl AsMut<[S]> for Tape { - fn as_mut(&mut self) -> &mut [S] { - &mut self.store - } -} - -impl core::borrow::Borrow<[S]> for Tape { - fn borrow(&self) -> &[S] { - &self.store - } -} - -impl core::borrow::BorrowMut<[S]> for Tape { - fn borrow_mut(&mut self) -> &mut [S] { - &mut self.store - } -} - -impl core::ops::Deref for Tape { - type Target = [S]; - - fn deref(&self) -> &Self::Target { - &self.store - } -} - -impl core::ops::DerefMut for Tape { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.store - } -} - -impl core::fmt::Display for Tape -where - S: core::fmt::Display, -{ - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - for (i, c) in self.store.iter().enumerate() { - match c { - b if i == self.pos => write!(f, "[{b}]")?, - _ => write!(f, "{c}")?, - } - } - Ok(()) - } -}