From 799f2e0e716be8e8612283ff2d95793fa1df56d0 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Fri, 23 Aug 2024 13:03:30 -0500 Subject: [PATCH 01/27] update Signed-off-by: Joe McCain III --- Cargo.toml | 2 +- rstm/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 40a9b7d..93e4efa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ keywords = [ "turing", "turing-machine", "utm" ] license = "Apache-2.0" readme = "README.md" repository = "https://github.com/FL03/rstm.git" -version = "0.0.3" +version = "0.0.4" [profile.dev] opt-level = 0 diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index 18c8ec2..f08bddf 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -65,7 +65,7 @@ thiserror.workspace = true [dependencies.rstm-core] path = "../core" -version = "0.0.3" +version = "0.0.4" [dependencies.serde] # default-features = false From 36fb659f104697c08f8787013f3a39a9834ac888 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Fri, 23 Aug 2024 13:24:23 -0500 Subject: [PATCH 02/27] update Signed-off-by: Joe McCain III --- core/src/actors/mod.rs | 7 +++++++ core/src/shift/mod.rs | 14 ++++++++++++-- core/src/traits/cspace.rs | 20 -------------------- core/src/traits/mod.rs | 2 -- core/src/traits/transform.rs | 7 ------- rstm/src/cspace/mod.rs | 25 +++++++++++++++++++++++++ rstm/src/lib.rs | 23 +++++++++-------------- rstm/src/models/mod.rs | 12 ++++++++++++ rstm/src/{ => models}/turing.rs | 0 9 files changed, 65 insertions(+), 45 deletions(-) delete mode 100644 core/src/traits/cspace.rs create mode 100644 rstm/src/cspace/mod.rs create mode 100644 rstm/src/models/mod.rs rename rstm/src/{ => models}/turing.rs (100%) diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs index b8cff85..b4dc272 100644 --- a/core/src/actors/mod.rs +++ b/core/src/actors/mod.rs @@ -2,6 +2,10 @@ Appellation: actors Contrib: FL03 */ +//! # Actors +//! +//! An actor describes an abstract model of computation that may find the solution to any +//! computable sequence, or algorithm. #[doc(inline)] pub use self::{actor::Actor, exec::Executor}; @@ -15,9 +19,12 @@ pub(crate) mod prelude { use crate::{rules::Program, Alphabet}; +#[doc(hidden)] pub trait Model { type Alpha: Alphabet; } + +#[doc(hidden)] pub trait Runtime { fn load(&mut self, program: Program); diff --git a/core/src/shift/mod.rs b/core/src/shift/mod.rs index 7d7903b..ad21cdb 100644 --- a/core/src/shift/mod.rs +++ b/core/src/shift/mod.rs @@ -11,6 +11,7 @@ pub(crate) mod prelude { pub use super::direction::Direction; } +/// [Directional] pub trait Directional { fn direction(&self) -> Direction; } @@ -23,15 +24,24 @@ pub trait IntoDirection { fn into_direction(self) -> Direction; } +/// [`Shift`] describes a generalized shift operation; +/// w.r.t. Turing machines, Moore (1990) describes a shift operation as a _movement_ of the +/// tape head +pub trait Shift { + type Output; + + fn shift(&self, step: T) -> Self::Output; +} + /* ************* Implementations ************* */ impl AsDirection for T where - T: Clone + Into, + T: Clone + IntoDirection, { fn as_direction(&self) -> Direction { - self.clone().into() + self.clone().into_direction() } } diff --git a/core/src/traits/cspace.rs b/core/src/traits/cspace.rs deleted file mode 100644 index c78b063..0000000 --- a/core/src/traits/cspace.rs +++ /dev/null @@ -1,20 +0,0 @@ -/* - Appellation: fsm - Contrib: FL03 -*/ - -pub trait Point { - type Elem; -} - -pub trait RawSpace { - type Elem; - - private!(); -} - -pub trait Space: RawSpace {} - -pub trait ConfigSpace { - type Space; -} diff --git a/core/src/traits/mod.rs b/core/src/traits/mod.rs index b8a0271..056187d 100644 --- a/core/src/traits/mod.rs +++ b/core/src/traits/mod.rs @@ -10,8 +10,6 @@ pub(crate) mod increment; pub(crate) mod symbolic; pub(crate) mod transform; -#[doc(hidden)] -pub mod cspace; #[doc(hidden)] pub mod io; diff --git a/core/src/traits/transform.rs b/core/src/traits/transform.rs index faabec5..9f96bea 100644 --- a/core/src/traits/transform.rs +++ b/core/src/traits/transform.rs @@ -3,14 +3,7 @@ Contrib: FL03 */ -/// [`Shift`] describes a generalized shift operation; -/// w.r.t. Turing machines, Moore (1990) describes a shift operation as a _movement_ of the -/// tape head -pub trait Shift { - type Output; - fn shift(&self, tape: &T) -> Self::Output; -} /// [`Transform`] is describes a binary operation capable of applying some transformation. /// More commonly, the typical "rustic" manner of which an object is transformed is through /// the [`map`] method, which applies a function to a value and returns a new value. diff --git a/rstm/src/cspace/mod.rs b/rstm/src/cspace/mod.rs new file mode 100644 index 0000000..5c3bd09 --- /dev/null +++ b/rstm/src/cspace/mod.rs @@ -0,0 +1,25 @@ +/* + Appellation: cspace + Contrib: FL03 +*/ +//! # Configuration Space (`C`) +//! +//! Configuration space `C` is the set of all possible configurations `q` of a system where +//! `q in Q`. + +/// The [`Point`] trait describes a point in a space. +pub trait Point { + type Elem; +} + +/// [RawSpace] describes +pub unsafe trait RawSpace { + type Elem: Point; + +} + +/// [Space] describes a space. +pub trait Space: RawSpace { + +} + diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index 04b9f08..19e62e7 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -7,27 +7,22 @@ //! `rstm` is a Rust library dedicated to the construction and execution of Turing Machines. //! The crate is designed to be flexible and easy to use while preserving the abstract nature //! of the models. -//! -//! Actors are one of the primary focuses of the library, designed to essentially mimic the -//! behavior of a smart-contract in reverse. Actors provide an _actionable_ or computable -//! surface for workloads to be executed on. -//! -#![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::turing::Turm; - -#[macro_use] -pub(crate) mod macros {} +pub use self::models::Turm; +#[doc(inline)] +pub use rstm_core::*; -pub mod turing; +#[doc(hidden)] +pub mod cspace; +pub mod models; pub mod prelude { - pub use crate::turing::Turm; + pub use super::models::prelude::*; + pub use rstm_core::prelude::*; } diff --git a/rstm/src/models/mod.rs b/rstm/src/models/mod.rs new file mode 100644 index 0000000..07e6e9d --- /dev/null +++ b/rstm/src/models/mod.rs @@ -0,0 +1,12 @@ +/* + Appellation: models + Contrib: FL03 +*/ +#[doc(inline)] +pub use self::turing::Turm; + +pub mod turing; + +pub(crate) mod prelude { + pub use super::turing::Turm; +} \ No newline at end of file diff --git a/rstm/src/turing.rs b/rstm/src/models/turing.rs similarity index 100% rename from rstm/src/turing.rs rename to rstm/src/models/turing.rs From 118a49fd0a024e8cac66ee422e5dcad7233dfd06 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Thu, 29 Aug 2024 10:32:07 -0500 Subject: [PATCH 03/27] create a new experimental crate`rstm-rulial` and begin working towards a `no-std` compatible core library Signed-off-by: Joe McCain III --- Cargo.toml | 3 +- core/Cargo.toml | 12 +-- core/src/actors/mod.rs | 4 +- core/src/error.rs | 28 ++++- core/src/lib.rs | 2 +- core/src/rules/builders/instructions.rs | 5 +- core/src/rules/program.rs | 2 - core/src/shift/mod.rs | 2 +- core/src/state/halt/wrap.rs | 21 +++- core/src/tape/hash_tape.rs | 79 ++++++++++---- core/src/tape/mod.rs | 2 +- core/src/traits/transform.rs | 1 - rstm/benches/default.rs | 81 +++++++++++++++ rstm/examples/basic.rs | 4 +- rstm/src/cspace/mod.rs | 25 ----- rstm/src/lib.rs | 4 +- rstm/src/models/{turing.rs => base.rs} | 12 +-- rstm/src/models/mod.rs | 8 +- rulial/Cargo.toml | 51 +++++++++ rulial/src/lib.rs | 23 ++++ rulial/src/macros.rs | 4 + rulial/src/seal.rs | 35 +++++++ rulial/src/space/mod.rs | 133 ++++++++++++++++++++++++ rulial/src/space/point.rs | 27 +++++ rulial/tests/default.rs | 17 +++ 25 files changed, 501 insertions(+), 84 deletions(-) create mode 100644 rstm/benches/default.rs delete mode 100644 rstm/src/cspace/mod.rs rename rstm/src/models/{turing.rs => base.rs} (96%) create mode 100644 rulial/Cargo.toml create mode 100644 rulial/src/lib.rs create mode 100644 rulial/src/macros.rs create mode 100644 rulial/src/seal.rs create mode 100644 rulial/src/space/mod.rs create mode 100644 rulial/src/space/point.rs create mode 100644 rulial/tests/default.rs diff --git a/Cargo.toml b/Cargo.toml index 93e4efa..623c88c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,8 @@ exclude = [ members = [ "rstm", - "core", + "core", + "rulial", ] resolver = "2" diff --git a/core/Cargo.toml b/core/Cargo.toml index 48eb54e..531a04c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,7 +14,7 @@ version.workspace = true [features] default = [ - "alloc", + "std", ] full = [ @@ -44,11 +44,11 @@ tracing = [ ] # ********* [FF] Environments ********* -# std = [ -# "alloc", -# "serde?/std", -# "strum/std", -# ] +std = [ + "alloc", + "serde?/std", + "strum/std", +] [lib] bench = true diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs index b4dc272..ec0cb80 100644 --- a/core/src/actors/mod.rs +++ b/core/src/actors/mod.rs @@ -3,8 +3,8 @@ Contrib: FL03 */ //! # Actors -//! -//! An actor describes an abstract model of computation that may find the solution to any +//! +//! An actor describes an abstract model of computation that may find the solution to any //! computable sequence, or algorithm. #[doc(inline)] pub use self::{actor::Actor, exec::Executor}; diff --git a/core/src/error.rs b/core/src/error.rs index 5a41b0d..f6d8b74 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -14,8 +14,18 @@ pub enum StateError { } #[derive( - Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, strum::VariantNames, thiserror::Error, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + strum::EnumDiscriminants, + strum::VariantNames, + thiserror::Error, )] +#[strum_discriminants(derive(Hash, Ord, PartialOrd))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum Error { #[error("[Execution Error] {0}")] @@ -64,6 +74,22 @@ impl Error { pub fn state_not_found() -> Self { Error::StateError(StateError::StateNotFound) } + + pub fn message(&self) -> String { + match self { + Error::ExecutionError(message) => message.clone(), + Error::IndexOutOfBounds { index, len } => { + format!( + "Out of Bounds: {} is out of bounds for a length of {}", + index, len + ) + } + Error::RuntimeError(message) => message.clone(), + Error::StateError(err) => err.to_string(), + Error::TransformationError(message) => message.clone(), + Error::Unknown(message) => message.clone(), + } + } } impl From<&str> for Error { diff --git a/core/src/lib.rs b/core/src/lib.rs index 0051933..dc5ef72 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -5,7 +5,7 @@ //! # rstm-core //! -// #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "alloc")] extern crate alloc; diff --git a/core/src/rules/builders/instructions.rs b/core/src/rules/builders/instructions.rs index a5182a9..4ebe5fc 100644 --- a/core/src/rules/builders/instructions.rs +++ b/core/src/rules/builders/instructions.rs @@ -2,9 +2,12 @@ Appellation: instructions Contrib: FL03 */ +use crate::{Head, State, Tail}; +use std::collections::HashMap; + #[derive(Default)] pub struct RulesetBuilder { pub(crate) initial_state: Option>, - pub(crate) rules: Vec>, + pub(crate) rules: HashMap, Tail>, } \ No newline at end of file diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index 99fa028..88d33d9 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -8,8 +8,6 @@ use std::vec; type Ruleset = Vec>; -// type Ruleset = std::collections::HashMap, Tail>; - #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Program { diff --git a/core/src/shift/mod.rs b/core/src/shift/mod.rs index ad21cdb..24a85a9 100644 --- a/core/src/shift/mod.rs +++ b/core/src/shift/mod.rs @@ -11,7 +11,7 @@ pub(crate) mod prelude { pub use super::direction::Direction; } -/// [Directional] +/// [Directional] pub trait Directional { fn direction(&self) -> Direction; } diff --git a/core/src/state/halt/wrap.rs b/core/src/state/halt/wrap.rs index 6355915..f643151 100644 --- a/core/src/state/halt/wrap.rs +++ b/core/src/state/halt/wrap.rs @@ -6,8 +6,23 @@ use crate::state::{Halt, State}; /// [HaltState] extends the [State] by allowing for an 'imaginary' state that is not actually /// part of the machine's state space. -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, strum::EnumDiscriminants, strum::EnumIs,)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize), strum_discriminants(derive(serde::Deserialize, serde::Serialize)))] +#[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + strum::EnumDiscriminants, + strum::EnumIs, +)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + strum_discriminants(derive(serde::Deserialize, serde::Serialize)) +)] #[strum_discriminants(name(HaltTag), derive(Hash, Ord, PartialOrd))] pub enum HaltState { Halt(Halt), @@ -77,4 +92,4 @@ impl From> for HaltState { fn from(halt: Halt) -> Self { Self::Halt(halt) } -} \ No newline at end of file +} diff --git a/core/src/tape/hash_tape.rs b/core/src/tape/hash_tape.rs index 47d302d..ce68707 100644 --- a/core/src/tape/hash_tape.rs +++ b/core/src/tape/hash_tape.rs @@ -2,13 +2,11 @@ Appellation: hash_tape Contrib: FL03 */ -// #![cfg(feature = "std")] +#![cfg(feature = "std")] use crate::shift::Direction; use std::collections::hash_map::{self, HashMap}; -pub trait HashIndex: Eq + core::hash::Hash + core::ops::Neg {} - -pub type Hdx = isize; +pub(crate) type Hdx = isize; #[derive(Clone, Debug, Default)] pub struct HashTape { @@ -25,25 +23,34 @@ impl HashTape { ticks: 0, } } - - pub fn reset(&mut self) { - self.cursor = 0; - self.store.clear(); - self.ticks = 0; - } - + /// Returns the current position of the head. pub fn cursor(&self) -> Hdx { self.cursor } - + /// Returns the total number of steps taken by the head. pub fn ticks(&self) -> usize { self.ticks } - + + pub fn clear(&mut self) { + self.cursor = 0; + self.store.clear(); + self.ticks = 0; + } + pub fn entry(&mut self, index: Hdx) -> hash_map::Entry { self.store.entry(index) } + /// Returns true if the tape contains the given index. + pub fn contains_key(&self, index: Hdx) -> bool { + self.store.contains_key(&index) + } + /// Returns true if the tape contains the given value. + pub fn contains_value(&self, value: &V) -> bool where V: PartialEq { + self.values().any(|v| v == value) + } + /// Returns a reference to the value at the given index. pub fn get(&self, index: Hdx) -> Option<&V> { self.store.get(&index) } @@ -59,19 +66,22 @@ impl HashTape { pub fn is_empty(&self) -> bool { self.store.is_empty() } + /// Returns an immutable iterator over the tape. + pub fn iter(&self) -> hash_map::Iter { + self.store.iter() + } + /// Returns a mutable iterator over the tape. + pub fn iter_mut(&mut self) -> hash_map::IterMut { + self.store.iter_mut() + } + /// Returns an iterator over the keys of the tape. + pub fn keys(&self) -> hash_map::Keys { + self.store.keys() + } /// Returns the number of elements in the tape. pub fn len(&self) -> usize { self.store.len() } - /// Removes the value at the given index. - pub fn remove(&mut self, index: Hdx) -> Option { - self.store.remove(&index) - } - /// Shifts the cursor in the given direction. - pub fn shift(&mut self, direction: Direction) { - self.cursor += direction; - self.ticks += 1; - } /// Returns a mutable reference to the value of the head at the current position; on empty, /// the given value is inserted and returned. pub fn or_insert(&mut self, default: V) -> &mut V { @@ -93,12 +103,35 @@ impl HashTape { { self.store.entry(self.cursor).or_default() } + /// Removes the value at the given index. + pub fn remove(&mut self, index: Hdx) -> Option { + self.store.remove(&index) + } + /// Returns an iterator over the values of the tape. + pub fn values(&self) -> hash_map::Values { + self.store.values() + } + + /// Shifts the cursor in the given direction. + pub fn shift(&mut self, direction: Direction) { + self.cursor += direction; + self.ticks += 1; + } + /// Returns a reference to the value at the current cursor position. pub fn read(&self) -> Option<&V> { self.store.get(&self.cursor) } - pub fn write(&mut self, value: V) { + pub fn read_or_default(&mut self) -> &V + where + V: Default, + { + self.or_default() + } + + pub fn write(&mut self, step: Direction, value: V) { let _ = self.store.insert(self.cursor, value); + self.shift(step); } } diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index 3f52730..d93cccd 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -11,7 +11,7 @@ pub use self::tape::StdTape; pub(crate) mod tape; -#[doc(hidden)] +#[cfg(feature = "std")] pub mod hash_tape; pub(crate) mod prelude { diff --git a/core/src/traits/transform.rs b/core/src/traits/transform.rs index 9f96bea..2dea121 100644 --- a/core/src/traits/transform.rs +++ b/core/src/traits/transform.rs @@ -3,7 +3,6 @@ Contrib: FL03 */ - /// [`Transform`] is describes a binary operation capable of applying some transformation. /// More commonly, the typical "rustic" manner of which an object is transformed is through /// the [`map`] method, which applies a function to a value and returns a new value. diff --git a/rstm/benches/default.rs b/rstm/benches/default.rs new file mode 100644 index 0000000..2169b51 --- /dev/null +++ b/rstm/benches/default.rs @@ -0,0 +1,81 @@ +/* + Appellation: default + Contrib: FL03 +*/ +#![feature(test)] +extern crate test; + +use test::Bencher; + +// bench: find the `BENCH_SIZE` first terms of the fibonacci sequence +static BENCH_SIZE: usize = 20; + +// function to benchmark must be annotated with `#[bench]` +#[bench] +fn recursive_fibonacci(b: &mut Bencher) { + // exact code to benchmark must be passed as a closure to the iter + // method of Bencher + b.iter(|| (0..BENCH_SIZE).map(fib::fibonacci).collect::>()) +} + +#[bench] +fn iterative_fibonacci(b: &mut Bencher) { + b.iter(|| fib::Fibonacci::seq().take(BENCH_SIZE).collect::>()) +} + +pub mod fib { + + /// [fibonacci] calculates the nth term of the fibonacci sequence using recursion; this + /// implementation is not recommended for large values of n and is simply used as a + /// benchmark. + pub fn fibonacci(n: usize) -> u32 { + if n < 2 { + 1 + } else { + fibonacci(n - 1) + fibonacci(n - 2) + } + } + + /// [Fibonacci] implements the fibonacci sequence as an [Iterator] + #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + pub struct Fibonacci { + pub curr: u32, + next: u32, + } + + impl Fibonacci { + pub fn new(curr: u32, next: u32) -> Self { + Self { curr, next } + } + + pub fn seq() -> Self { + Self::new(1, 1) + } + + pub fn get(&self) -> u32 { + self.curr + } + + pub fn get_next(&self) -> u32 { + self.next + } + } + + impl Default for Fibonacci { + fn default() -> Self { + Self { curr: 1, next: 1 } + } + } + + impl Iterator for Fibonacci { + type Item = u32; + + fn next(&mut self) -> Option { + use core::mem::replace; + let next = self.get() + self.next; + let curr = replace(&mut self.next, next); + + Some(replace(&mut self.curr, curr)) + } + } +} diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 0872b87..c6a243d 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -4,7 +4,7 @@ */ extern crate rstm; -use rstm::{ruleset, Program, State, StdTape, Turm}; +use rstm::{ruleset, Program, State, StdTM, StdTape}; fn main() -> Result<(), Box> { _tracing("debug"); @@ -25,7 +25,7 @@ fn main() -> Result<(), Box> { // create a new tape with the data let tape = StdTape::from_iter(alpha); // create a new instance of the machine - let tm = Turm::new(program, tape); + let tm = StdTM::new(program, tape); tm.execute()?; Ok(()) } diff --git a/rstm/src/cspace/mod.rs b/rstm/src/cspace/mod.rs deleted file mode 100644 index 5c3bd09..0000000 --- a/rstm/src/cspace/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -/* - Appellation: cspace - Contrib: FL03 -*/ -//! # Configuration Space (`C`) -//! -//! Configuration space `C` is the set of all possible configurations `q` of a system where -//! `q in Q`. - -/// The [`Point`] trait describes a point in a space. -pub trait Point { - type Elem; -} - -/// [RawSpace] describes -pub unsafe trait RawSpace { - type Elem: Point; - -} - -/// [Space] describes a space. -pub trait Space: RawSpace { - -} - diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index 19e62e7..7aaea4a 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -13,12 +13,10 @@ extern crate alloc; #[doc(inline)] -pub use self::models::Turm; +pub use self::models::StdTM; #[doc(inline)] pub use rstm_core::*; -#[doc(hidden)] -pub mod cspace; pub mod models; pub mod prelude { diff --git a/rstm/src/models/turing.rs b/rstm/src/models/base.rs similarity index 96% rename from rstm/src/models/turing.rs rename to rstm/src/models/base.rs index 49deae4..ab852fa 100644 --- a/rstm/src/models/turing.rs +++ b/rstm/src/models/base.rs @@ -3,32 +3,31 @@ Contrib: FL03 */ - use crate::prelude::{Error, HaltState, Head, StdTape, Symbolic, Tail}; use crate::rules::Program; use crate::state::State; -/// # Turing Machine ([Turm]) +/// # Turing Machine ([StdTm]) /// /// 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 Turm { +pub struct StdTM { pub(crate) program: Program, pub(crate) state: HaltState, pub(crate) tape: StdTape, } -impl Turm { +impl StdTM { pub fn new(program: Program, tape: StdTape) -> Self where Q: Clone + Default, S: Default, { let state = program.initial_state().cloned(); - Turm { + StdTM { program, state: HaltState::state(state), tape, @@ -113,7 +112,6 @@ impl Turm { symbol, }) = self.program.get_ref(self.read()?) { - // self.tape.update(direction, symbol.clone()); self.state = state.cloned().into(); @@ -123,7 +121,7 @@ impl Turm { } } -impl core::iter::Iterator for Turm +impl core::iter::Iterator for StdTM where Q: Clone + PartialEq + 'static, S: Clone + PartialEq, diff --git a/rstm/src/models/mod.rs b/rstm/src/models/mod.rs index 07e6e9d..90027e3 100644 --- a/rstm/src/models/mod.rs +++ b/rstm/src/models/mod.rs @@ -3,10 +3,10 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::turing::Turm; +pub use self::base::StdTM; -pub mod turing; +pub mod base; pub(crate) mod prelude { - pub use super::turing::Turm; -} \ No newline at end of file + pub use super::base::StdTM; +} diff --git a/rulial/Cargo.toml b/rulial/Cargo.toml new file mode 100644 index 0000000..ecc7f58 --- /dev/null +++ b/rulial/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "rulial" +authors.workspace = true +categories.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +license.workspace = true +readme.workspace = true +repository.workspace = true +version.workspace = true + +[features] +default = [ + "alloc", +] + + +# ********* [FF] Dependencies ********* +alloc = [ + "rstm-core/alloc", + "serde?/alloc", +] + +serde = [ + "dep:serde", +] + +# ********* [FF] Environments ********* +# std = [ +# "alloc", +# "rstm-core/std", +# "serde?/std", +# ] + +[build-dependencies] + +[dependencies] +thiserror.workspace = true +smart-default.workspace = true +[dependencies.rstm-core] +default-features = false +path = "../core" +version = "0.0.4" + +[dependencies.serde] +default-features = false +features = ["derive"] +optional = true +version = "1" diff --git a/rulial/src/lib.rs b/rulial/src/lib.rs new file mode 100644 index 0000000..b2baf10 --- /dev/null +++ b/rulial/src/lib.rs @@ -0,0 +1,23 @@ +/* + Appellation: rstm-rulial + Contrib: FL03 +*/ +//! # Rulial +//! +//! +#[doc(inline)] +pub use self::space::BasePoint; + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[macro_use] +pub(crate) mod macros; +#[macro_use] +pub(crate) mod seal; + +pub mod space; + +pub mod prelude { + pub use super::space::prelude::*; +} diff --git a/rulial/src/macros.rs b/rulial/src/macros.rs new file mode 100644 index 0000000..b64b585 --- /dev/null +++ b/rulial/src/macros.rs @@ -0,0 +1,4 @@ +/* + Appellation: macros + Contrib: FL03 +*/ diff --git a/rulial/src/seal.rs b/rulial/src/seal.rs new file mode 100644 index 0000000..72f553e --- /dev/null +++ b/rulial/src/seal.rs @@ -0,0 +1,35 @@ +/* + Appellation: seal + Contrib: FL03 +*/ +#![allow(unused)] +//! The public parts of this private module are used to create traits +//! that cannot be implemented outside of our own crate. This way we +//! can feel free to extend those traits without worrying about it +//! being a breaking change for other implementations. +//! + +#[doc(hidden)] +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 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::Sealer; + }; +} + +macro_rules! seal { + () => { + fn __private__(&self) -> $crate::seal::Sealer { + $crate::seal::Sealer + } + }; +} diff --git a/rulial/src/space/mod.rs b/rulial/src/space/mod.rs new file mode 100644 index 0000000..028a3fc --- /dev/null +++ b/rulial/src/space/mod.rs @@ -0,0 +1,133 @@ +/* + Appellation: space + Contrib: FL03 +*/ +//! # Rulial Space +//! +//! +//! ## Definition +//! +//! Configuration space `C` is the set of all possible configurations `q` of a system where +//! `q in Q`. +#[doc(inline)] +pub use self::point::BasePoint; + +pub(crate) mod point; + +pub(crate) mod prelude { + pub use super::point::*; + pub use super::{RawPoint, RawSpace, Space}; +} + +/// The [`RawPoint`] trait describes a point in a space. +pub trait RawPoint { + type Elem; + + fn as_ptr(&self) -> *const Self::Elem; + + fn as_mut_ptr(&mut self) -> *mut Self::Elem; + + fn as_slice(&self) -> &[Self::Elem]; + + fn as_mut_slice(&mut self) -> &mut [Self::Elem]; + + fn len(&self) -> usize; + + fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +/// [RawSpace] describes +pub unsafe trait RawSpace { + type Elem: RawPoint; +} + +/// [Space] describes a space. +pub trait Space: RawSpace {} + +/* + ************* Implementations ************* +*/ +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +impl RawPoint for [A] { + type Elem = A; + + fn as_ptr(&self) -> *const Self::Elem { + self.as_ptr() + } + + fn as_mut_ptr(&mut self) -> *mut Self::Elem { + self.as_mut_ptr() + } + + fn as_slice(&self) -> &[Self::Elem] { + &self + } + + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self + } + + fn len(&self) -> usize { + self.len() + } +} + +#[cfg(feature = "alloc")] +impl RawPoint for Vec { + type Elem = T; + + fn as_ptr(&self) -> *const Self::Elem { + Vec::as_ptr(self) + } + + fn as_mut_ptr(&mut self) -> *mut Self::Elem { + Vec::as_mut_ptr(self) + } + + fn as_slice(&self) -> &[Self::Elem] { + Vec::as_slice(self) + } + + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + Vec::as_mut_slice(self) + } + + fn len(&self) -> usize { + Vec::len(self) + } + + fn is_empty(&self) -> bool { + Vec::is_empty(self) + } +} + +impl RawPoint for BasePoint +where + S: RawPoint, +{ + type Elem = S::Elem; + + fn as_ptr(&self) -> *const Self::Elem { + self.data.as_ptr() + } + + fn as_mut_ptr(&mut self) -> *mut Self::Elem { + self.data.as_mut_ptr() + } + + fn as_slice(&self) -> &[Self::Elem] { + self.data.as_slice() + } + + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self.data.as_mut_slice() + } + + fn len(&self) -> usize { + self.data.len() + } +} diff --git a/rulial/src/space/point.rs b/rulial/src/space/point.rs new file mode 100644 index 0000000..efda7a6 --- /dev/null +++ b/rulial/src/space/point.rs @@ -0,0 +1,27 @@ +/* + Appellation: point + Contrib: FL03 +*/ +use super::RawPoint; + +/// A point in a space. +/// +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct BasePoint +where + S: RawPoint, +{ + pub(crate) data: S, +} + +impl BasePoint +where + S: RawPoint, +{ + pub fn new(data: S) -> Self { + Self { data } + } + + +} diff --git a/rulial/tests/default.rs b/rulial/tests/default.rs new file mode 100644 index 0000000..233a07a --- /dev/null +++ b/rulial/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); +} From 481663b0d6f532b94240430bb1725ab7126630db Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Fri, 30 Aug 2024 08:33:49 -0500 Subject: [PATCH 04/27] update Signed-off-by: Joe McCain III --- .github/workflows/crates.yml | 32 +---- .github/workflows/rust.yml | 32 ++--- core/src/lib.rs | 16 ++- core/src/shift/direction.rs | 214 +++------------------------- core/src/shift/mod.rs | 38 +---- core/src/tape/hash_tape.rs | 36 ++++- core/src/tape/mod.rs | 73 +--------- core/src/traits/convert.rs | 35 +++++ core/src/traits/execute.rs | 10 -- core/src/traits/mod.rs | 6 +- core/src/types/direction.rs | 262 +++++++++++++++++++++++++++++++++++ core/src/types/mod.rs | 4 +- rulial/Cargo.toml | 51 ------- rulial/src/lib.rs | 23 --- rulial/src/macros.rs | 4 - rulial/src/seal.rs | 35 ----- rulial/src/space/mod.rs | 133 ------------------ rulial/src/space/point.rs | 27 ---- rulial/tests/default.rs | 17 --- 19 files changed, 390 insertions(+), 658 deletions(-) create mode 100644 core/src/traits/convert.rs delete mode 100644 core/src/traits/execute.rs create mode 100644 core/src/types/direction.rs delete mode 100644 rulial/Cargo.toml delete mode 100644 rulial/src/lib.rs delete mode 100644 rulial/src/macros.rs delete mode 100644 rulial/src/seal.rs delete mode 100644 rulial/src/space/mod.rs delete mode 100644 rulial/src/space/point.rs delete mode 100644 rulial/tests/default.rs diff --git a/.github/workflows/crates.yml b/.github/workflows/crates.yml index e9c761d..f689017 100644 --- a/.github/workflows/crates.yml +++ b/.github/workflows/crates.yml @@ -6,6 +6,7 @@ concurrency: env: BASENAME: ${{ github.event.repository.name }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} CARGO_TERM_COLOR: always on: @@ -19,43 +20,18 @@ jobs: base: env: CRATE_NAME: ${{ github.event.repository.name }}-${{ matrix.suffix }} - name: Publish (${{ matrix.suffix }}) + name: Publish Base Modules 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 }} + - run: cargo publish --all-features -v -p ${{ env.CRATE_NAME }} publish: - name: Publish (${{ github.event.repository.name }}) + name: Publish SDK needs: base 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 932548a..74ebb0d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -11,10 +11,8 @@ env: on: pull_request: branches: [ main ] - push: - tags: [ v*.*.* ] release: - types: [ published ] + types: [ created ] repository_dispatch: types: [ rust ] schedule: @@ -28,33 +26,31 @@ jobs: name: Build strategy: matrix: - platform: [ ubuntu-latest ] + platform: [ macos-latest, ubuntu-latest, windows-latest ] toolchain: [ stable, nightly ] runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v4 - - name: setup (rustup) + - name: rustup run: | rustup default ${{ matrix.toolchain }} rustup update - - name: build (workspace) + - name: build run: cargo build --all-features -r -v --workspace - - name: cache - uses: actions/cache@v4 + - name: test + run: cargo test -v --workspace -F full + - name: benchmark + if: matrix.toolchain == 'nightly' + run: cargo bench -F full -v --workspace + - uses: actions/cache@v4 with: - key: cargo-${{ matrix.toolchain }}-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-cargo-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.lock') }} path: | ~/.cargo/registry ~/.cargo/git target/debug target/release restore-keys: | - cargo-${{ matrix.toolchain }}-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} - cargo-${{ matrix.toolchain }}-${{ runner.os }}- - cargo-${{ matrix.toolchain }}- - - name: cargo test (workspace) --full - run: cargo test -v --workspace -F full - - name: cargo (bench) - if: matrix.toolchain == 'nightly' - run: cargo bench -F full -v --workspace - + ${{ runner.os }}-cargo-${{ matrix.toolchain }}- + ${{ runner.os }}-cargo- + ${{ runner.os }}- diff --git a/core/src/lib.rs b/core/src/lib.rs index dc5ef72..708e52d 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -4,6 +4,19 @@ */ //! # rstm-core //! +//! The `rstm-core` crate provides the core functionality for the `rstm` library. +//! +//! ## Features +//! +//! ### Components +//! +//! - [x] Rules +//! - [x] States +//! +//! ### Tapes +//! +//! - [x] [StdTape] +//! - [x] [HashTape](tape::hash_tape::HashTape) #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "alloc")] @@ -14,10 +27,9 @@ pub use self::{ actors::Actor, error::Error, rules::{Program, Rule}, - shift::Direction, state::State, tape::StdTape, - traits::*, + traits::prelude::*, types::prelude::*, }; diff --git a/core/src/shift/direction.rs b/core/src/shift/direction.rs index 60ace26..3b36fd9 100644 --- a/core/src/shift/direction.rs +++ b/core/src/shift/direction.rs @@ -3,27 +3,32 @@ Contrib: FL03 */ -/// [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. +/// [LinearShift] #[derive( Clone, Copy, Debug, - Default, Eq, Hash, Ord, PartialEq, PartialOrd, + strum::EnumDiscriminants, + strum::EnumCount, + strum::EnumIs, +)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize), strum_discriminants(derive(serde::Deserialize, serde::Serialize)))] +#[strum(serialize_all = "lowercase")] +#[strum_discriminants(name(ShiftDirection), derive(Hash, + Ord, + PartialOrd, strum::AsRefStr, strum::Display, strum::EnumCount, + strum::EnumIs, strum::EnumIter, - strum::VariantNames, -)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[strum(serialize_all = "lowercase")] -pub enum Direction { + strum::VariantNames,), strum(serialize_all = "lowercase"))] +pub enum LinearShift { /// Represents a single left shift #[cfg_attr( feature = "serde", @@ -35,7 +40,7 @@ pub enum Direction { alias = "Left" ) )] - Left = -1, + Left(T), #[cfg_attr( feature = "serde", serde( @@ -47,8 +52,7 @@ pub enum Direction { ) )] /// Represents a single right shift - Right = 1, - #[default] + Right(T), #[cfg_attr( feature = "serde", serde( @@ -60,191 +64,5 @@ pub enum Direction { ) )] /// Represents no movement - 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 - } - /// 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, - } - } - /// Converts a [str] value into a [Direction] by matching the value to the corresponding - /// variant; defaults to [`Stay`](Direction::Stay) if the value does not match accepted - /// representations of neither [left](Direction::Left) nor [right](Direction::Right). - pub fn from_str(value: &str) -> Self { - match value { - "left" | "Left" | "LEFT" | "l" | "L" => Self::Left, - "right" | "Right" | "RIGHT" | "r" | "R" => Self::Right, - _ => Self::Stay, - } - } - /// Returns a [char] representation of the [direction](Direction). - /// - /// ### standard [char] representation - /// - /// 'L' => [Direction::Left] - /// 'R' => [Direction::Right] - /// 'S' => [Direction::Stay] - pub fn as_char(&self) -> char { - match self { - Self::Left => 'L', - Self::Right => 'R', - Self::Stay => 'S', - } - } - /// Returns a [str] representation of the [direction](Direction). - pub fn as_str(&self) -> &str { - match self { - Self::Left => "left", - Self::Right => "right", - Self::Stay => "stay", - } - } - - /// Applies the shift to the given position in the [direction](Direction) specified by the - /// current instance. This is done using the [`wrapping_add_signed`](usize::wrapping_add_signed) - /// method. - pub fn apply_unsigned(self, cur: usize) -> usize { - cur.wrapping_add_signed(self as isize) - } -} - -impl core::ops::Add for Direction -where - T: crate::Decrement + crate::Increment, -{ - type Output = T; - - fn add(self, rhs: T) -> Self::Output { - match self { - Self::Left => rhs.decrement(), - Self::Right => rhs.increment(), - Self::Stay => rhs, - } - } -} - -impl core::ops::Add for isize { - type Output = isize; - - fn add(self, rhs: Direction) -> Self::Output { - self + rhs as isize - } -} - -impl core::ops::Add for usize { - type Output = usize; - - fn add(self, rhs: Direction) -> Self::Output { - self.wrapping_add_signed(rhs as isize) - } -} - -impl core::ops::AddAssign for usize { - fn add_assign(&mut self, rhs: Direction) { - *self = core::ops::Add::add(*self, rhs); - } -} - -impl core::ops::AddAssign for isize { - fn add_assign(&mut self, rhs: Direction) { - *self = core::ops::Add::add(*self, rhs); - } -} - -mod impl_from { - use super::*; - use crate::shift::IntoDirection; - - 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, - } - } - } + Stay(T), } diff --git a/core/src/shift/mod.rs b/core/src/shift/mod.rs index 24a85a9..6844a87 100644 --- a/core/src/shift/mod.rs +++ b/core/src/shift/mod.rs @@ -3,25 +3,12 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::direction::Direction; +pub use self::direction::{LinearShift, ShiftDirection}; pub(crate) mod direction; pub(crate) mod prelude { - pub use super::direction::Direction; -} - -/// [Directional] -pub trait Directional { - fn direction(&self) -> Direction; -} -/// 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; + pub use super::direction::*; } /// [`Shift`] describes a generalized shift operation; @@ -32,24 +19,3 @@ pub trait Shift { fn shift(&self, step: T) -> Self::Output; } - -/* - ************* Implementations ************* -*/ -impl AsDirection for T -where - T: Clone + IntoDirection, -{ - fn as_direction(&self) -> Direction { - self.clone().into_direction() - } -} - -impl IntoDirection for T -where - T: Into, -{ - fn into_direction(self) -> Direction { - self.into() - } -} diff --git a/core/src/tape/hash_tape.rs b/core/src/tape/hash_tape.rs index ce68707..ffb8bc3 100644 --- a/core/src/tape/hash_tape.rs +++ b/core/src/tape/hash_tape.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ #![cfg(feature = "std")] -use crate::shift::Direction; +use crate::Direction; use std::collections::hash_map::{self, HashMap}; pub(crate) type Hdx = isize; @@ -23,6 +23,30 @@ impl HashTape { ticks: 0, } } + + pub fn from_data(data: HashMap) -> HashTape { + HashTape { + cursor: 0, + store: data, + ticks: 0, + } + } + + pub fn from_iter(iter: I) -> HashTape + where + I: IntoIterator, + { + HashTape { + cursor: 0, + store: HashMap::from_iter(iter), + ticks: 0, + } + } + + pub fn from_seq(seq: I) -> HashTape where I: IntoIterator { + let iter = seq.into_iter().enumerate().map(|(i, v)| (i as Hdx, v)); + Self::from_iter(iter) + } /// Returns the current position of the head. pub fn cursor(&self) -> Hdx { self.cursor @@ -31,13 +55,17 @@ impl HashTape { pub fn ticks(&self) -> usize { self.ticks } - + /// clears the tape. pub fn clear(&mut self) { self.cursor = 0; self.store.clear(); self.ticks = 0; } - + /// Returns the entry in the tape at the current index. + pub fn current_entry(&mut self) -> hash_map::Entry { + self.store.entry(self.cursor) + } + /// Returns a mutable entry in the tape at the given index. pub fn entry(&mut self, index: Hdx) -> hash_map::Entry { self.store.entry(index) } @@ -123,7 +151,7 @@ impl HashTape { self.store.get(&self.cursor) } - pub fn read_or_default(&mut self) -> &V + pub fn read_mut(&mut self) -> &mut V where V: Default, { diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index d93cccd..5dbc835 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -18,6 +18,8 @@ pub(crate) mod prelude { pub use super::tape::StdTape; } +use core::option::Option; + #[doc(hidden)] pub trait Mem { type Key; @@ -36,82 +38,16 @@ pub trait Mem { fn len(&self) -> usize; } -#[doc(hidden)] -/// [RawTape] defines the basic interface used for tape-like structures; i.e., a contiguous, -/// sequential array of elements. -pub trait RawTape { - type Elem; - - private!(); - - fn as_slice(&self) -> &[Self::Elem]; - - fn is_empty(&self) -> bool { - self.len() == 0 - } - - fn len(&self) -> usize { - self.as_slice().len() - } -} - -#[doc(hidden)] -/// [Tape] is a -pub trait Tape: RawTape { - type Idx; - - fn clear(&mut self); - - fn get(&self, idx: &Self::Idx) -> Option<&Self::Elem>; - - fn get_mut(&mut self, idx: &Self::Idx) -> Option<&mut Self::Elem>; - - fn insert(&mut self, idx: Self::Idx, elem: Self::Elem); -} - /* ************* Implementations ************* */ #[cfg(feature = "alloc")] use alloc::vec::Vec; +#[cfg(feature = "std")] use std::collections::HashMap; -impl RawTape for [T] { - type Elem = T; - - seal!(); - - fn as_slice(&self) -> &[Self::Elem] { - &self - } - - fn is_empty(&self) -> bool { - <[T]>::is_empty(self) - } - - fn len(&self) -> usize { - <[T]>::len(self) - } -} - -impl RawTape for Vec { - type Elem = T; - - seal!(); - - fn as_slice(&self) -> &[Self::Elem] { - Vec::as_slice(self) - } - - fn is_empty(&self) -> bool { - Vec::is_empty(self) - } - - fn len(&self) -> usize { - Vec::len(self) - } -} +#[cfg(feature = "alloc")] impl Mem for Vec { type Key = usize; type Value = V; @@ -147,6 +83,7 @@ impl Mem for Vec { } } +#[cfg(feature = "std")] impl Mem for HashMap where K: Eq + std::hash::Hash, diff --git a/core/src/traits/convert.rs b/core/src/traits/convert.rs new file mode 100644 index 0000000..46953b8 --- /dev/null +++ b/core/src/traits/convert.rs @@ -0,0 +1,35 @@ +/* + Appellation: convert + Contrib: FL03 +*/ +use crate::Direction; + +/// 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; +} + +/* + ************* Implementations ************* +*/ +impl AsDirection for T +where + T: Clone + IntoDirection, +{ + fn as_direction(&self) -> Direction { + self.clone().into_direction() + } +} + +impl IntoDirection for T +where + T: Into, +{ + fn into_direction(self) -> Direction { + self.into() + } +} diff --git a/core/src/traits/execute.rs b/core/src/traits/execute.rs deleted file mode 100644 index 7a9e427..0000000 --- a/core/src/traits/execute.rs +++ /dev/null @@ -1,10 +0,0 @@ -/* - Appellation: execute - Contrib: FL03 -*/ - -pub trait Execute { - type Output; - - fn execute(&self) -> Result; -} diff --git a/core/src/traits/mod.rs b/core/src/traits/mod.rs index 056187d..1eaa4b1 100644 --- a/core/src/traits/mod.rs +++ b/core/src/traits/mod.rs @@ -3,9 +3,9 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{execute::*, increment::*, symbolic::*, transform::*}; +pub use self::{convert::*, increment::*, symbolic::*, transform::*}; -pub(crate) mod execute; +pub(crate) mod convert; pub(crate) mod increment; pub(crate) mod symbolic; pub(crate) mod transform; @@ -14,7 +14,7 @@ pub(crate) mod transform; pub mod io; pub(crate) mod prelude { - pub use super::execute::*; + pub use super::convert::*; pub use super::increment::*; pub use super::symbolic::*; pub use super::transform::*; diff --git a/core/src/types/direction.rs b/core/src/types/direction.rs new file mode 100644 index 0000000..5e4f0c7 --- /dev/null +++ b/core/src/types/direction.rs @@ -0,0 +1,262 @@ +/* + Appellation: direction + Contrib: FL03 +*/ + +/// [Directional] describes a type containing a direction +pub trait Directional { + fn 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, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + strum::AsRefStr, + strum::Display, + strum::EnumCount, + strum::EnumIs, + strum::EnumIter, + strum::VariantArray, + strum::VariantNames, +)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[strum(serialize_all = "lowercase")] +pub enum Direction { + /// Represents a single left shift + #[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" + ) + )] + /// Represents a single right shift + Right = 1, + #[cfg_attr( + feature = "serde", + serde( + alias = "stay", + alias = "s", + alias = "S", + alias = "STAY", + alias = "Stay" + ) + )] + /// Represents no movement + 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 + } + /// 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, + } + } + /// Converts a [str] value into a [Direction] by matching the value to the corresponding + /// variant; defaults to [`Stay`](Direction::Stay) if the value does not match accepted + /// representations of neither [left](Direction::Left) nor [right](Direction::Right). + pub fn from_str(value: &str) -> Self { + match value { + "left" | "Left" | "LEFT" | "l" | "L" => Self::Left, + "right" | "Right" | "RIGHT" | "r" | "R" => Self::Right, + _ => Self::Stay, + } + } + /// Returns a [char] representation of the [direction](Direction). + /// + /// ### standard [char] representation + /// + /// 'L' => [Direction::Left] + /// 'R' => [Direction::Right] + /// 'S' => [Direction::Stay] + pub fn as_char(&self) -> char { + match self { + Self::Left => 'L', + Self::Right => 'R', + Self::Stay => 'S', + } + } + /// Returns a [str] representation of the [direction](Direction). + pub fn as_str(&self) -> &str { + match self { + Self::Left => "left", + Self::Right => "right", + Self::Stay => "stay", + } + } + + /// Applies the shift to the given position in the [direction](Direction) specified by the + /// current instance. This is done using the [`wrapping_add_signed`](usize::wrapping_add_signed) + /// method. + pub fn apply_unsigned(self, cur: usize) -> usize { + cur.wrapping_add_signed(self as isize) + } +} + +impl Default for Direction { + fn default() -> Self { + Self::Stay + } +} + +impl core::ops::Add for Direction +where + T: crate::Decrement + crate::Increment, +{ + type Output = T; + + fn add(self, rhs: T) -> Self::Output { + match self { + Self::Left => rhs.decrement(), + Self::Right => rhs.increment(), + Self::Stay => rhs, + } + } +} + +impl core::ops::Add for isize { + type Output = isize; + + fn add(self, rhs: Direction) -> Self::Output { + self + rhs as isize + } +} + +impl core::ops::Add for usize { + type Output = usize; + + fn add(self, rhs: Direction) -> Self::Output { + self.wrapping_add_signed(rhs as isize) + } +} + +impl core::ops::AddAssign for usize { + fn add_assign(&mut self, rhs: Direction) { + *self = core::ops::Add::add(*self, rhs); + } +} + +impl core::ops::AddAssign for isize { + fn add_assign(&mut self, rhs: Direction) { + *self = core::ops::Add::add(*self, rhs); + } +} + +mod impl_from { + use super::*; + use crate::IntoDirection; + + 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 index 8ebfe12..7ebdaa1 100644 --- a/core/src/types/mod.rs +++ b/core/src/types/mod.rs @@ -3,8 +3,9 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{head::Head, tail::Tail}; +pub use self::{direction::Direction, head::Head, tail::Tail}; +pub(crate) mod direction; pub(crate) mod head; pub(crate) mod tail; @@ -12,6 +13,7 @@ pub(crate) mod tail; pub mod cursor; pub(crate) mod prelude { + pub use super::direction::*; pub use super::head::Head; pub use super::tail::Tail; pub use super::IndexedHead; diff --git a/rulial/Cargo.toml b/rulial/Cargo.toml deleted file mode 100644 index ecc7f58..0000000 --- a/rulial/Cargo.toml +++ /dev/null @@ -1,51 +0,0 @@ -[package] -name = "rulial" -authors.workspace = true -categories.workspace = true -description.workspace = true -edition.workspace = true -homepage.workspace = true -keywords.workspace = true -license.workspace = true -readme.workspace = true -repository.workspace = true -version.workspace = true - -[features] -default = [ - "alloc", -] - - -# ********* [FF] Dependencies ********* -alloc = [ - "rstm-core/alloc", - "serde?/alloc", -] - -serde = [ - "dep:serde", -] - -# ********* [FF] Environments ********* -# std = [ -# "alloc", -# "rstm-core/std", -# "serde?/std", -# ] - -[build-dependencies] - -[dependencies] -thiserror.workspace = true -smart-default.workspace = true -[dependencies.rstm-core] -default-features = false -path = "../core" -version = "0.0.4" - -[dependencies.serde] -default-features = false -features = ["derive"] -optional = true -version = "1" diff --git a/rulial/src/lib.rs b/rulial/src/lib.rs deleted file mode 100644 index b2baf10..0000000 --- a/rulial/src/lib.rs +++ /dev/null @@ -1,23 +0,0 @@ -/* - Appellation: rstm-rulial - Contrib: FL03 -*/ -//! # Rulial -//! -//! -#[doc(inline)] -pub use self::space::BasePoint; - -#[cfg(feature = "alloc")] -extern crate alloc; - -#[macro_use] -pub(crate) mod macros; -#[macro_use] -pub(crate) mod seal; - -pub mod space; - -pub mod prelude { - pub use super::space::prelude::*; -} diff --git a/rulial/src/macros.rs b/rulial/src/macros.rs deleted file mode 100644 index b64b585..0000000 --- a/rulial/src/macros.rs +++ /dev/null @@ -1,4 +0,0 @@ -/* - Appellation: macros - Contrib: FL03 -*/ diff --git a/rulial/src/seal.rs b/rulial/src/seal.rs deleted file mode 100644 index 72f553e..0000000 --- a/rulial/src/seal.rs +++ /dev/null @@ -1,35 +0,0 @@ -/* - Appellation: seal - Contrib: FL03 -*/ -#![allow(unused)] -//! The public parts of this private module are used to create traits -//! that cannot be implemented outside of our own crate. This way we -//! can feel free to extend those traits without worrying about it -//! being a breaking change for other implementations. -//! - -#[doc(hidden)] -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 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::Sealer; - }; -} - -macro_rules! seal { - () => { - fn __private__(&self) -> $crate::seal::Sealer { - $crate::seal::Sealer - } - }; -} diff --git a/rulial/src/space/mod.rs b/rulial/src/space/mod.rs deleted file mode 100644 index 028a3fc..0000000 --- a/rulial/src/space/mod.rs +++ /dev/null @@ -1,133 +0,0 @@ -/* - Appellation: space - Contrib: FL03 -*/ -//! # Rulial Space -//! -//! -//! ## Definition -//! -//! Configuration space `C` is the set of all possible configurations `q` of a system where -//! `q in Q`. -#[doc(inline)] -pub use self::point::BasePoint; - -pub(crate) mod point; - -pub(crate) mod prelude { - pub use super::point::*; - pub use super::{RawPoint, RawSpace, Space}; -} - -/// The [`RawPoint`] trait describes a point in a space. -pub trait RawPoint { - type Elem; - - fn as_ptr(&self) -> *const Self::Elem; - - fn as_mut_ptr(&mut self) -> *mut Self::Elem; - - fn as_slice(&self) -> &[Self::Elem]; - - fn as_mut_slice(&mut self) -> &mut [Self::Elem]; - - fn len(&self) -> usize; - - fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -/// [RawSpace] describes -pub unsafe trait RawSpace { - type Elem: RawPoint; -} - -/// [Space] describes a space. -pub trait Space: RawSpace {} - -/* - ************* Implementations ************* -*/ -#[cfg(feature = "alloc")] -use alloc::vec::Vec; - -impl RawPoint for [A] { - type Elem = A; - - fn as_ptr(&self) -> *const Self::Elem { - self.as_ptr() - } - - fn as_mut_ptr(&mut self) -> *mut Self::Elem { - self.as_mut_ptr() - } - - fn as_slice(&self) -> &[Self::Elem] { - &self - } - - fn as_mut_slice(&mut self) -> &mut [Self::Elem] { - self - } - - fn len(&self) -> usize { - self.len() - } -} - -#[cfg(feature = "alloc")] -impl RawPoint for Vec { - type Elem = T; - - fn as_ptr(&self) -> *const Self::Elem { - Vec::as_ptr(self) - } - - fn as_mut_ptr(&mut self) -> *mut Self::Elem { - Vec::as_mut_ptr(self) - } - - fn as_slice(&self) -> &[Self::Elem] { - Vec::as_slice(self) - } - - fn as_mut_slice(&mut self) -> &mut [Self::Elem] { - Vec::as_mut_slice(self) - } - - fn len(&self) -> usize { - Vec::len(self) - } - - fn is_empty(&self) -> bool { - Vec::is_empty(self) - } -} - -impl RawPoint for BasePoint -where - S: RawPoint, -{ - type Elem = S::Elem; - - fn as_ptr(&self) -> *const Self::Elem { - self.data.as_ptr() - } - - fn as_mut_ptr(&mut self) -> *mut Self::Elem { - self.data.as_mut_ptr() - } - - fn as_slice(&self) -> &[Self::Elem] { - self.data.as_slice() - } - - fn as_mut_slice(&mut self) -> &mut [Self::Elem] { - self.data.as_mut_slice() - } - - fn len(&self) -> usize { - self.data.len() - } -} diff --git a/rulial/src/space/point.rs b/rulial/src/space/point.rs deleted file mode 100644 index efda7a6..0000000 --- a/rulial/src/space/point.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - Appellation: point - Contrib: FL03 -*/ -use super::RawPoint; - -/// A point in a space. -/// -#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct BasePoint -where - S: RawPoint, -{ - pub(crate) data: S, -} - -impl BasePoint -where - S: RawPoint, -{ - pub fn new(data: S) -> Self { - Self { data } - } - - -} diff --git a/rulial/tests/default.rs b/rulial/tests/default.rs deleted file mode 100644 index 233a07a..0000000 --- a/rulial/tests/default.rs +++ /dev/null @@ -1,17 +0,0 @@ -/* - 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); -} From d8595c92afa91a833bcf9ef1c77ea3bc58a7d201 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Fri, 30 Aug 2024 14:17:11 -0500 Subject: [PATCH 05/27] update Signed-off-by: Joe McCain III --- Cargo.toml | 3 +- core/Cargo.toml | 12 ++ core/src/actors/engine.rs | 70 ++++++++ core/src/actors/exec.rs | 11 +- core/src/actors/mod.rs | 3 + core/src/error.rs | 7 + core/src/lib.rs | 10 +- core/src/macros/states.rs | 25 +++ core/src/rules/mod.rs | 17 +- core/src/rules/program.rs | 18 +- core/src/rules/{workload.rs => ruleset.rs} | 186 ++++++++++++++------ core/src/shift/direction.rs | 30 ++-- core/src/state/halt/mod.rs | 23 ++- core/src/state/halt/state.rs | 35 ++-- core/src/state/mod.rs | 70 ++++++-- core/src/state/state.rs | 169 +++++++++++++----- core/src/tape/hash_tape.rs | 14 +- core/src/tape/mod.rs | 1 - core/src/traits/mod.rs | 8 +- core/src/traits/{symbolic.rs => symbols.rs} | 0 core/src/traits/transform.rs | 14 -- core/src/types/direction.rs | 1 - core/tests/rules.rs | 38 ++++ core/tests/state.rs | 75 ++++++++ core/tests/tape.rs | 16 ++ rstm/Cargo.toml | 4 +- 26 files changed, 681 insertions(+), 179 deletions(-) create mode 100644 core/src/actors/engine.rs rename core/src/rules/{workload.rs => ruleset.rs} (63%) rename core/src/traits/{symbolic.rs => symbols.rs} (100%) delete mode 100644 core/src/traits/transform.rs create mode 100644 core/tests/rules.rs create mode 100644 core/tests/state.rs create mode 100644 core/tests/tape.rs diff --git a/Cargo.toml b/Cargo.toml index 623c88c..93e4efa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,7 @@ exclude = [ members = [ "rstm", - "core", - "rulial", + "core", ] resolver = "2" diff --git a/core/Cargo.toml b/core/Cargo.toml index 531a04c..a6fa2ad 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -56,6 +56,18 @@ crate-type = ["cdylib", "rlib"] doctest = false test = true +[[test]] +name = "actor" +required-features = ["alloc"] + +[[test]] +name = "rules" +required-features = ["alloc"] + +[[test]] +name = "tape" +required-features = ["alloc"] + [dependencies] thiserror.workspace = true paste.workspace = true diff --git a/core/src/actors/engine.rs b/core/src/actors/engine.rs new file mode 100644 index 0000000..a7cb565 --- /dev/null +++ b/core/src/actors/engine.rs @@ -0,0 +1,70 @@ +/* + Appellation: engine + Contrib: FL03 +*/ +use crate::state::RawState; +use crate::{Error, Head, Program}; + +use std::collections::HashMap; + +pub struct Engine +where + Q: RawState, +{ + pub(crate) program: Program, + pub(crate) scope: Head, // Head, + pub(crate) tape: HashMap, +} + +impl Engine +where + Q: RawState, +{ + // pub fn new(initial_state: State) -> Self { + // Self { + // program: Program::new().initial_state(state), + // scope: Head { + // state: initial_state, + // symbol: 0, + // }, + // tape: HashMap::new(), + // } + // } + pub fn with_input(self, input: I) -> Self + where + I: IntoIterator, + { + Self { + tape: HashMap::from_iter(input.into_iter().enumerate().map(|(i, a)| (i as isize, a))), + ..self + } + } + pub fn with_program(self, program: Program) -> Self { + Self { program, ..self } + } + pub fn read(&self) -> Option<&A> { + self.tape.get(&self.scope.symbol) + } + + pub fn write(&mut self, symbol: A) { + self.tape.insert(self.scope.symbol, symbol); + } + + pub fn process(&mut self) -> Result<(), Error> + where + A: crate::Symbolic, + Q: Clone + Eq + std::hash::Hash, + { + let symbol = self.read().expect("no symbol found"); + if let Some(rule) = self.program.get(self.scope.state(), symbol) { + let next = Head { + state: rule.state.clone(), + symbol: self.scope.symbol + rule.direction, + }; + self.write(rule.symbol); + self.scope = next; + } + + Ok(()) + } +} diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 3207ed9..5a6db9c 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -90,14 +90,17 @@ where } // read the tape let head = if let Ok(cur) = self.read() { - cur.cloned() + cur } else { #[cfg(feature = "tracing")] - tracing::warn!("Unable to locate the value of the head..."); - Head::from_state(self.actor.state().cloned()) + tracing::warn!("[Index Error] the current position ({pos}) of the head is out of bounds, assuming the symbol to be its default value...", pos = self.actor.head.symbol); + Head { + state: self.actor.state(), + symbol: &S::default(), + } }; // execute the program - if let Some(tail) = self.program.get(&head).cloned() { + if let Some(tail) = self.program.get(head.state, head.symbol).cloned() { // process the instruction self.actor.process(tail.clone()); // return the head diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs index ec0cb80..054328d 100644 --- a/core/src/actors/mod.rs +++ b/core/src/actors/mod.rs @@ -12,6 +12,9 @@ pub use self::{actor::Actor, exec::Executor}; pub(crate) mod actor; pub(crate) mod exec; +#[doc(hidden)] +pub mod engine; + pub(crate) mod prelude { pub use super::actor::Actor; pub use super::exec::Executor; diff --git a/core/src/error.rs b/core/src/error.rs index f6d8b74..569c226 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -38,6 +38,8 @@ pub enum Error { StateError(#[from] StateError), #[error("[Transformation Error]: {0}")] TransformationError(String), + #[error("[Type Error] {0}")] + TypeError(String), #[error("[Unknown Error] {0}")] Unknown(String), } @@ -63,6 +65,10 @@ impl Error { Error::TransformationError(message.to_string()) } + pub fn type_error(message: impl ToString) -> Self { + Error::TypeError(message.to_string()) + } + pub fn unknown(message: impl ToString) -> Self { Error::Unknown(message.to_string()) } @@ -87,6 +93,7 @@ impl Error { Error::RuntimeError(message) => message.clone(), Error::StateError(err) => err.to_string(), Error::TransformationError(message) => message.clone(), + Error::TypeError(message) => message.clone(), Error::Unknown(message) => message.clone(), } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 708e52d..5819240 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -5,16 +5,16 @@ //! # rstm-core //! //! The `rstm-core` crate provides the core functionality for the `rstm` library. -//! +//! //! ## Features -//! +//! //! ### Components -//! +//! //! - [x] Rules //! - [x] States -//! +//! //! ### Tapes -//! +//! //! - [x] [StdTape] //! - [x] [HashTape](tape::hash_tape::HashTape) diff --git a/core/src/macros/states.rs b/core/src/macros/states.rs index ada53e4..6755abb 100644 --- a/core/src/macros/states.rs +++ b/core/src/macros/states.rs @@ -3,6 +3,31 @@ Contrib: FL03 */ +macro_rules! getter { + (@impl $vis:vis $T:ident($($field:tt)*)) => { + $vis fn into_inner(self) -> Self::Inner { + self.$($field)* + } + + $vis const fn get(&self) -> &Self::Inner { + &self.$($field)* + } + + $vis fn get_mut(&mut self) -> &mut Self::Inner { + &mut self.$($field)* + } + + $vis fn set(&mut self, inner: Self::Inner) { + self.$($field)* = inner; + } + }; + ($($vis:vis $T:ident($($field:tt)*)),* $(,)?) => { + $( + getter!(@impl $vis $T($($field)*)); + )* + }; +} + #[macro_export] macro_rules! state { ($state:expr) => { diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index bdd22b8..172dbbf 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -7,12 +7,12 @@ pub use self::{ builders::{ProgramBuilder, RuleBuilder}, program::Program, rule::Rule, + ruleset::RuleSet, }; pub(crate) mod program; pub(crate) mod rule; - -pub mod workload; +pub mod ruleset; #[doc(hidden)] pub(crate) mod builders { @@ -30,6 +30,19 @@ pub(crate) mod prelude { use crate::{Direction, Head, State, Symbolic, Tail}; +pub trait Rules { + type Key: Scope; + type Val: Directive; + + fn get(&self, key: &Self::Key) -> Option<&Self::Val>; + + fn insert(&mut self, key: Self::Key, val: Self::Val) -> Option; + + fn remove(&mut self, key: &Self::Key) -> Option; + + fn contains_key(&self, key: &Self::Key) -> bool; +} + pub trait Transition { fn direction(&self) -> Direction; diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index 88d33d9..d0f802f 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -70,8 +70,22 @@ impl Program { pub fn iter_mut(&mut self) -> core::slice::IterMut> { self.rules.iter_mut() } + + pub fn get(&self, State(state): State<&Q>, symbol: &S) -> Option<&Tail> + where + Q: PartialEq, + S: PartialEq, + { + self.iter().find_map(|i| { + if i.head().state() == state && i.head().symbol() == symbol { + Some(i.tail()) + } else { + None + } + }) + } /// Returns a collection of tails for a given head. - pub fn get(&self, head: &Head) -> Option<&Tail> + pub fn get_head(&self, head: &Head) -> Option<&Tail> where Q: PartialEq, S: PartialEq, @@ -148,7 +162,7 @@ where type Output = Tail; fn index(&self, index: Head) -> &Self::Output { - self.get(&index).unwrap() + self.get_head(&index).unwrap() } } diff --git a/core/src/rules/workload.rs b/core/src/rules/ruleset.rs similarity index 63% rename from core/src/rules/workload.rs rename to core/src/rules/ruleset.rs index a66d7d6..fb85747 100644 --- a/core/src/rules/workload.rs +++ b/core/src/rules/ruleset.rs @@ -2,73 +2,57 @@ Appellation: workload Contrib: FL03 */ -// #![cfg(feature = "std")] +#![cfg(feature = "std")] use super::Rule; use crate::{Head, State, Tail}; use std::collections::hash_map::{self, HashMap}; #[derive(Clone, Debug, Default)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct RuleSet -where - Q: Eq + core::hash::Hash, - S: Eq + core::hash::Hash, -{ - pub(crate) initial_state: State, +#[cfg_attr(feature = "serde", derive(serde::Serialize))] +pub struct RuleSet { + pub(crate) initial_state: Option>, pub(crate) rules: HashMap, Tail>, } -impl RuleSet -where - Q: Eq + core::hash::Hash, - S: Eq + core::hash::Hash, -{ - pub fn new() -> Self - where - Q: Default, - { +impl RuleSet { + pub fn new() -> Self { Self { - initial_state: State::default(), + initial_state: None, rules: HashMap::new(), } } - pub fn from_state(State(initial_state): State) -> Self { + pub fn from_state(initial_state: State) -> Self { Self { - initial_state: State(initial_state), + initial_state: Some(initial_state), rules: HashMap::new(), } } pub fn from_iter(iter: I) -> Self where - Q: Default, + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, I: IntoIterator, Tail)>, { Self { - initial_state: State::default(), + initial_state: None, rules: HashMap::from_iter(iter), } } pub fn from_rules(iter: I) -> Self where - Q: Default, + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, I: IntoIterator>, { - let mut rules = HashMap::new(); - for rule in iter { - rules.insert(rule.head, rule.tail); - } - Self { - initial_state: State::default(), - rules, - } + Self::from_iter(iter.into_iter().map(|rule| (rule.head, rule.tail))) } - - pub fn with_initial_state(self, State(state): State) -> Self { + /// configures the ruleset with the given initial state + pub fn with_initial_state(self, state: State) -> Self { Self { - initial_state: State(state), + initial_state: Some(state), ..self } } @@ -76,92 +60,190 @@ where pub fn with_instructions( self, instructions: impl IntoIterator, Tail)>, - ) -> Self { - let mut rules = HashMap::new(); - for (head, tail) in instructions { - rules.insert(head, tail); + ) -> Self + where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, + { + Self { + rules: HashMap::from_iter(instructions), + ..self } - Self { rules, ..self } } + /// Returns an instance of [State] which owns a reference to the interval value. - pub fn initial_state(&self) -> State<&'_ Q> { - self.initial_state.to_ref() + pub fn initial_state(&self) -> Option> { + self.initial_state.as_ref().map(|state| state.to_ref()) } + /// Returns an immutable reference to the set of rules. pub const fn rules(&self) -> &HashMap, Tail> { &self.rules } + /// Returns a mutable reference to the set of rules. pub fn rules_mut(&mut self) -> &mut HashMap, Tail> { &mut self.rules } + /// Clears the set of rules. pub fn clear(&mut self) { self.rules.clear(); } + /// Returns an the entry for the given head within the set of rules. - pub fn entry(&mut self, head: Head) -> hash_map::Entry, Tail> { + pub fn entry(&mut self, head: Head) -> hash_map::Entry, Tail> + where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, + { self.rules.entry(head) } /// Returns an immutable reference to the tail of the rule for the given head; returns none /// if the head is not found. - pub fn get(&self, head: &Head) -> Option<&Tail> { + pub fn get_head(&self, head: &Head) -> Option<&Tail> + where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, + { self.rules.get(head) } + /// Returns a mutable reference to the tail of the rule for the given head; returns none if /// the head is not found. - pub fn get_mut(&mut self, head: &Head) -> Option<&mut Tail> { + pub fn get_mut(&mut self, head: &Head) -> Option<&mut Tail> + where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, + { self.rules.get_mut(head) } + /// Returns the tail of the rule for the given head; returns none if the head is not found /// within the set of rules. - pub fn get_ref(&self, head: &Head) -> Option> { - self.get(head).map(|tail| tail.to_ref()) + pub fn get_ref(&self, head: &Head) -> Option> + where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, + { + self.get_head(head).map(|tail| tail.to_ref()) } + /// Inserts a new rule into the set of rules. - pub fn insert(&mut self, head: Head, tail: Tail) { + pub fn insert(&mut self, head: Head, tail: Tail) + where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, + { self.rules.insert(head, tail); } + /// Inserts a new rule into the set of rules. - pub fn insert_rule(&mut self, rule: Rule) { + pub fn insert_rule(&mut self, rule: Rule) + where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, + { self.insert(rule.head, rule.tail); } + /// Returns true if the set of rules is empty. pub fn is_empty(&self) -> bool { self.rules.is_empty() } + /// Returns the number of rules in the set. pub fn len(&self) -> usize { self.rules.len() } + /// Returns a mutable reference to the tail of the rule for the given head; inserts the /// tail if the head is not found. - pub fn or_insert(&mut self, head: Head, tail: Tail) -> &mut Tail { + pub fn or_insert(&mut self, head: Head, tail: Tail) -> &mut Tail + where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, + { self.rules.entry(head).or_insert(tail) } + /// Returns a mutable reference to the tail of the rule for the given head; inserts the /// tail if the head is not found. pub fn or_insert_with(&mut self, head: Head, f: F) -> &mut Tail where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, F: FnOnce() -> Tail, { self.rules.entry(head).or_insert_with(f) } + /// Returns a mutable reference to the tail of the rule for the given head; inserts the /// default tail if the head is not found. pub fn or_insert_default(&mut self, head: Head) -> &mut Tail where - Q: Default, - S: Default, + Q: Default + Eq + core::hash::Hash, + S: Default + Eq + core::hash::Hash, { self.or_insert(head, Tail::default()) } + /// Removes a rule from the set of rules. - pub fn remove(&mut self, head: &Head) -> Option> { + pub fn remove(&mut self, head: &Head) -> Option> + where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, + { self.rules.remove(head) } } +#[cfg(feature = "serde")] +impl<'a, Q, S> serde::Deserialize<'a> for RuleSet +where + Q: Eq + core::hash::Hash + serde::Deserialize<'a>, + S: Eq + core::hash::Hash + serde::Deserialize<'a>, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'a>, + { + struct RuleSetVisitor { + _phantom: core::marker::PhantomData<(Q, S)>, + } + + impl<'a, Q, S> serde::de::Visitor<'a> for RuleSetVisitor + where + Q: Eq + core::hash::Hash + serde::Deserialize<'a>, + S: Eq + core::hash::Hash + serde::Deserialize<'a>, + { + type Value = RuleSet; + + fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + formatter.write_str("a map of rules") + } + + fn visit_map(self, mut map: A) -> Result + where + A: serde::de::MapAccess<'a>, + { + let mut rules = HashMap::with_capacity(map.size_hint().unwrap_or(0)); + while let Some((head, tail)) = map.next_entry()? { + rules.insert(head, tail); + } + Ok(RuleSet { + initial_state: None, + rules, + }) + } + } + + deserializer.deserialize_map(RuleSetVisitor { + _phantom: core::marker::PhantomData, + }) + } +} + impl core::iter::Extend<(Head, Tail)> for RuleSet where Q: Eq + core::hash::Hash, diff --git a/core/src/shift/direction.rs b/core/src/shift/direction.rs index 3b36fd9..1352fb7 100644 --- a/core/src/shift/direction.rs +++ b/core/src/shift/direction.rs @@ -17,17 +17,27 @@ strum::EnumCount, strum::EnumIs, )] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize), strum_discriminants(derive(serde::Deserialize, serde::Serialize)))] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + strum_discriminants(derive(serde::Deserialize, serde::Serialize)) +)] #[strum(serialize_all = "lowercase")] -#[strum_discriminants(name(ShiftDirection), derive(Hash, - Ord, - PartialOrd, - strum::AsRefStr, - strum::Display, - strum::EnumCount, - strum::EnumIs, - strum::EnumIter, - strum::VariantNames,), strum(serialize_all = "lowercase"))] +#[strum_discriminants( + name(ShiftDirection), + derive( + Hash, + Ord, + PartialOrd, + strum::AsRefStr, + strum::Display, + strum::EnumCount, + strum::EnumIs, + strum::EnumIter, + strum::VariantNames, + ), + strum(serialize_all = "lowercase") +)] pub enum LinearShift { /// Represents a single left shift #[cfg_attr( diff --git a/core/src/state/halt/mod.rs b/core/src/state/halt/mod.rs index 338b783..6c0b9d0 100644 --- a/core/src/state/halt/mod.rs +++ b/core/src/state/halt/mod.rs @@ -11,13 +11,30 @@ pub use self::{state::Halt, wrap::HaltState}; pub(crate) mod state; pub(crate) mod wrap; -use crate::state::RawState; +use super::RawState; #[doc(hidden)] -pub trait Haltable { +pub trait Haltable { const HALT: bool = true; - type State: RawState; + type State: RawState; private!(); } + +/* + ************* Implementations ************* +*/ +use crate::state::State; + +impl Haltable for Halt { + type State = State; + + seal!(); +} + +impl Haltable for State> { + type State = State; + + seal!(); +} diff --git a/core/src/state/halt/state.rs b/core/src/state/halt/state.rs index dd7162e..35e2eb3 100644 --- a/core/src/state/halt/state.rs +++ b/core/src/state/halt/state.rs @@ -2,7 +2,7 @@ Appellation: halting Contrib: FL03 */ -use crate::state::{halt::Haltable, State}; +use crate::state::{RawState, State}; #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] @@ -12,7 +12,7 @@ impl Halt { pub fn new(halt: Q) -> Self { Self(halt) } - + #[inline] pub fn into_inner(self) -> Q { self.0 } @@ -24,10 +24,29 @@ impl Halt { pub fn get_mut(&mut self) -> &mut Q { &mut self.0 } + /// Replaces the inner value of the halted state with the given value, returning the + /// previous value. + pub fn replace(&mut self, halt: Q) -> Q { + core::mem::replace(&mut self.0, halt) + } + pub fn reset(&mut self) + where + Q: Default, + { + self.set(Default::default()); + } + /// Sets the inner value of the halted state to that of the given value. pub fn set(&mut self, halt: Q) { self.0 = halt; } + /// Swaps the inner value of the halted state with that of the given state. + pub fn swap(&mut self, other: &mut S) + where + S: RawState, + { + core::mem::swap(&mut self.0, other.get_mut()); + } /// Converts the halted state into a new [State] with an immutable reference to the inner value. pub fn as_state(&self) -> State> { State(Halt(&self.0)) @@ -88,12 +107,8 @@ impl From> for Halt { } } -impl Haltable for Halt { - type State = State; - seal!(); -} - -impl Haltable for State> { - type State = State; - seal!(); +impl From> for State { + fn from(Halt(state): Halt) -> Self { + Self(state) + } } diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index 8683728..47a7a56 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -25,37 +25,73 @@ pub(crate) mod prelude { pub type AnyState = State>; -pub trait BaseState: Eq + PartialOrd + core::hash::Hash {} - +/// [RawState] is a trait describing objects capable of being used as states in our library. +/// The trait contains a single associated trait, the context, or inner value of the state. #[doc(hidden)] pub trait RawState { - type Ctx; -} + type Inner; -#[doc(hidden)] -pub trait Stated: RawState { - fn cloned(&self) -> Self - where - Q: Clone; - fn copied(&self) -> Self - where - Q: Copy; + private!(); + + fn into_inner(self) -> Self::Inner; + + fn get(&self) -> &Self::Inner; + + fn get_mut(&mut self) -> &mut Self::Inner; + + fn set(&mut self, inner: Self::Inner); } #[doc(hidden)] pub trait Stateful { - type State: RawState; + type State: RawState; +} + +pub trait StatefulView: Stateful { + fn state(&self) -> &Self::State; } /* ************* Implementations ************* */ -impl RawState for Halt { - type Ctx = Q; +macro_rules! impl_raw_state { + (@impl $T:ident($($field:tt)*)) => { + impl RawState for $T { + type Inner = Q; + + seal!(); + + fn into_inner(self) -> Self::Inner { + self.$($field)* + } + + fn get(&self) -> &Self::Inner { + &self.$($field)* + } + + fn get_mut(&mut self) -> &mut Self::Inner { + &mut self.$($field)* + } + + fn set(&mut self, inner: Self::Inner) { + self.$($field)* = inner; + } + } + }; + ($($T:ident($($field:tt)*)),* $(,)?) => { + $( + impl_raw_state!(@impl $T($($field)*)); + )* + }; +} + +impl_raw_state! { + Halt(0), + State(0), } -impl RawState for State { - type Ctx = Q; +impl Stateful for Halt { + type State = State; } impl Stateful for State { diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 52693c6..17ee038 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -2,7 +2,8 @@ Appellation: state Contrib: FL03 */ -use crate::state::Halt; +use super::{Halt, RawState}; +use crate::Error; use std::sync::Arc; /// #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] @@ -14,7 +15,14 @@ impl State { pub fn new(state: Q) -> Self { Self(state) } - + /// Casts the state to a new type, returning a new instance of [State]. + /// + /// ### Saftey + /// + /// * + pub unsafe fn cast(self) -> State { + State(core::ptr::read(&self.0 as *const Q as *const R)) + } /// Returns an immutable reference to the state. pub const fn get(&self) -> &Q { &self.0 @@ -27,10 +35,50 @@ impl State { pub fn into_inner(self) -> Q { 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(&Q) -> R, + { + State(f(self.get())) + } + /// [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.get_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(Q) -> R, + { + State(f(self.into_inner())) + } + /// Replaces the state with a new value, returning the old value. + pub fn replace(&mut self, state: Q) -> Q { + core::mem::replace(&mut self.0, state) + } + /// Clears the state, setting it to its default value. + pub fn reset(&mut self) + where + Q: Default, + { + self.set(Default::default()); + } /// Sets the state to a new value. pub fn set(&mut self, state: Q) { self.0 = state; } + /// Replaces the state with a new value, returning the old value. + pub fn swap(&mut self, other: &mut S) + where + S: RawState, + { + core::mem::swap(&mut self.0, other.get_mut()); + } /// Returns a halted state with an immutable reference to the state. pub fn as_halt(&self) -> State> { State(Halt(self)) @@ -41,48 +89,40 @@ impl State { } /// Returns a new state with a boxed inner value. pub fn boxed(self) -> State> { - State(Box::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(&Q) -> R, - { - State(f(self.get())) + self.map_once(Box::new) } - /// [State::map_mut] applies a [`FnMut`] closure to the state, returing the transformed state. - pub fn map_mut(mut self, f: &mut F) -> State + /// Converts the inner type into a boxed "any" state, returning a new instance of state + pub fn as_any(&self) -> State> where - F: FnMut(&mut Q) -> R, + Q: Clone + 'static, { - State(f(self.get_mut())) + State(Box::new(self.get().clone())) } - /// Maps the state to a new state using a closure that takes the state by value. - pub fn map_once(self, f: F) -> State + /// Converts the inner type into a boxed "any" state, returning a new instance of state + pub fn into_any(self) -> State> where - F: FnOnce(State) -> R, + Q: 'static, { - State(f(self)) + State(Box::new(self.into_inner())) } /// Wraps the inner value of the state with an [`Arc`] and returns a new instance of [State] pub fn shared(self) -> State> { - State(Arc::new(self.0)) + self.map_once(Arc::new) } /// Returns a shared reference to the state. pub fn to_shared(&self) -> State> where Q: Clone, { - State(Arc::new(self.0.clone())) + State(Arc::new(self.get().clone())) } /// Returns a state with an owned inner value. pub fn to_ref(&self) -> State<&Q> { - State(&self.0) + State(self.get()) } /// Returns a state with a mutable reference to the inner value. pub fn to_mut(&mut self) -> State<&mut Q> { - State(&mut self.0) + State(self.get_mut()) } /// Returns the `name` of the generic inner type, `Q`. pub fn get_inner_type_name(&self) -> &'static str { @@ -108,6 +148,32 @@ impl State { } } +impl State<()> { + /// Creates a new instance of [State] with an empty state. + pub fn empty() -> Self { + Self(()) + } +} + +impl State> { + /// Downcasts the state to a new type, returning a new instance of [State]. + pub fn downcast(self) -> Result>, Error> + where + Q: core::any::Any, + { + self.into_inner() + .downcast() + .map(State) + .map_err(|_| Error::type_error("Failed to downcast state")) + } + + pub fn downcast_ref(&self) -> Option> + where + Q: core::any::Any, + { + self.get().downcast_ref().map(State) + } +} impl State> { /// Creates a new instance of [State] from a [Halt] state. pub fn halted(Halt(inner): Halt) -> Self { @@ -153,13 +219,13 @@ impl<'a, Q> State<&'a mut Q> { } } -impl AsRef for State { +impl core::convert::AsRef for State { fn as_ref(&self) -> &Q { &self.0 } } -impl AsMut for State { +impl core::convert::AsMut for State { fn as_mut(&mut self) -> &mut Q { &mut self.0 } @@ -212,18 +278,18 @@ 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 PartialEq for State +impl core::cmp::PartialEq for State where - Q: PartialEq, + Q: core::cmp::PartialEq, { fn eq(&self, other: &Q) -> bool { self.get().eq(other) } } -impl PartialOrd for State +impl core::cmp::PartialOrd for State where - Q: PartialOrd, + Q: core::cmp::PartialOrd, { fn partial_cmp(&self, other: &Q) -> Option { self.get().partial_cmp(other) @@ -237,7 +303,20 @@ impl From for State { } macro_rules! impl_ops { - (@impl $trait:ident.$call:ident) => { + (@alt $trait:ident::$call:ident) => { + impl ::core::ops::$trait for State + where + Q: ::core::ops::$trait, + R: $crate::state::RawState, + { + type Output = State; + + fn $call(self, rhs: State) -> Self::Output { + State(::core::ops::$trait::$call(self.into_inner(), rhs.into_inner())) + } + } + }; + (@impl $trait:ident::$call:ident) => { impl ::core::ops::$trait for State where Q: ::core::ops::$trait, @@ -245,7 +324,7 @@ macro_rules! impl_ops { type Output = State; fn $call(self, rhs: State) -> Self::Output { - State(::core::ops::$trait::$call(self.0, rhs.0)) + State(::core::ops::$trait::$call(self.into_inner(), rhs.into_inner())) } } @@ -256,7 +335,7 @@ macro_rules! impl_ops { type Output = State; fn $call(self, rhs: Q) -> Self::Output { - State(::core::ops::$trait::$call(self.0, rhs)) + State(::core::ops::$trait::$call(self.into_inner(), rhs)) } } @@ -267,7 +346,7 @@ macro_rules! impl_ops { { fn [<$call _assign>](&mut self, rhs: State) { - ::core::ops::[<$trait Assign>]::[<$call _assign>](self.get_mut(), rhs.0) + ::core::ops::[<$trait Assign>]::[<$call _assign>](self.get_mut(), rhs.into_inner()) } } impl ::core::ops::[<$trait Assign>] for State @@ -281,22 +360,22 @@ macro_rules! impl_ops { } } }; - ($($trait:ident.$call:ident),* $(,)?) => { + ($($trait:ident::$call:ident),* $(,)?) => { $( - impl_ops!(@impl $trait.$call); + impl_ops!(@impl $trait::$call); )* }; } impl_ops! { - Add.add, - BitAnd.bitand, - BitOr.bitor, - BitXor.bitxor, - Div.div, - Mul.mul, - Rem.rem, - Shl.shl, - Shr.shr, - Sub.sub, + Add::add, + BitAnd::bitand, + BitOr::bitor, + BitXor::bitxor, + Div::div, + Mul::mul, + Rem::rem, + Shl::shl, + Shr::shr, + Sub::sub, } diff --git a/core/src/tape/hash_tape.rs b/core/src/tape/hash_tape.rs index ffb8bc3..ec051dc 100644 --- a/core/src/tape/hash_tape.rs +++ b/core/src/tape/hash_tape.rs @@ -43,7 +43,10 @@ impl HashTape { } } - pub fn from_seq(seq: I) -> HashTape where I: IntoIterator { + pub fn from_seq(seq: I) -> HashTape + where + I: IntoIterator, + { let iter = seq.into_iter().enumerate().map(|(i, v)| (i as Hdx, v)); Self::from_iter(iter) } @@ -75,7 +78,10 @@ impl HashTape { self.store.contains_key(&index) } /// Returns true if the tape contains the given value. - pub fn contains_value(&self, value: &V) -> bool where V: PartialEq { + pub fn contains_value(&self, value: &V) -> bool + where + V: PartialEq, + { self.values().any(|v| v == value) } /// Returns a reference to the value at the given index. @@ -139,13 +145,13 @@ impl HashTape { pub fn values(&self) -> hash_map::Values { self.store.values() } - + /// Shifts the cursor in the given direction. pub fn shift(&mut self, direction: Direction) { self.cursor += direction; self.ticks += 1; } - + /// Returns a reference to the value at the current cursor position. pub fn read(&self) -> Option<&V> { self.store.get(&self.cursor) diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index 5dbc835..0887f1b 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -46,7 +46,6 @@ use alloc::vec::Vec; #[cfg(feature = "std")] use std::collections::HashMap; - #[cfg(feature = "alloc")] impl Mem for Vec { type Key = usize; diff --git a/core/src/traits/mod.rs b/core/src/traits/mod.rs index 1eaa4b1..5d9fbec 100644 --- a/core/src/traits/mod.rs +++ b/core/src/traits/mod.rs @@ -3,12 +3,11 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{convert::*, increment::*, symbolic::*, transform::*}; +pub use self::{convert::*, increment::*, symbols::*}; pub(crate) mod convert; pub(crate) mod increment; -pub(crate) mod symbolic; -pub(crate) mod transform; +pub(crate) mod symbols; #[doc(hidden)] pub mod io; @@ -16,6 +15,5 @@ pub mod io; pub(crate) mod prelude { pub use super::convert::*; pub use super::increment::*; - pub use super::symbolic::*; - pub use super::transform::*; + pub use super::symbols::*; } diff --git a/core/src/traits/symbolic.rs b/core/src/traits/symbols.rs similarity index 100% rename from core/src/traits/symbolic.rs rename to core/src/traits/symbols.rs diff --git a/core/src/traits/transform.rs b/core/src/traits/transform.rs deleted file mode 100644 index 2dea121..0000000 --- a/core/src/traits/transform.rs +++ /dev/null @@ -1,14 +0,0 @@ -/* - Appellation: transform - Contrib: FL03 -*/ - -/// [`Transform`] is describes a binary operation capable of applying some transformation. -/// More commonly, the typical "rustic" manner of which an object is transformed is through -/// the [`map`] method, which applies a function to a value and returns a new value. -pub trait Transform { - type Output; - /// [`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`]. - fn transform(&self, delta: T) -> Self::Output; -} diff --git a/core/src/types/direction.rs b/core/src/types/direction.rs index 5e4f0c7..be4aa7d 100644 --- a/core/src/types/direction.rs +++ b/core/src/types/direction.rs @@ -8,7 +8,6 @@ pub trait Directional { fn 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( diff --git a/core/tests/rules.rs b/core/tests/rules.rs new file mode 100644 index 0000000..3856338 --- /dev/null +++ b/core/tests/rules.rs @@ -0,0 +1,38 @@ +/* + Appellation: rules + Contrib: FL03 +*/ +extern crate rstm_core as rstm; + +use rstm::rules::Program; +use rstm::{ruleset, Direction, Head, State, Tail}; + +#[test] +fn ruleset() { + let rules = ruleset![ + (0, 0) -> Right(1, 1), + (0, 1) -> Left(-1, 0), + (1, 0) -> Right(1, 1), + (1, 1) -> Left(-1, 1), + (-1, 0) -> Right(0, 0), + (-1, 1) -> Left(0, 1), + ]; + // validate the number of rules within the ruleset + assert_eq!(rules.len(), 6); + // create a new program using the ruleset + let program = Program::new() + .initial_state(State(0isize)) + .rules(rules) + .build(); + // validate the number of rules within the program + assert_eq!(rules.len(), program.len()); + // compare the inner value of the initial state + assert_eq!(program.initial_state(), &0); + // create a new head for a rule within the program + let head = Head::new(State(0), 0); + // retrieve and validate the tail for the given head + assert_eq!( + program.get_head(&head), + Some(&Tail::new(Direction::Right, State(1), 1)) + ) +} diff --git a/core/tests/state.rs b/core/tests/state.rs new file mode 100644 index 0000000..82af521 --- /dev/null +++ b/core/tests/state.rs @@ -0,0 +1,75 @@ +/* + Appellation: state + Contrib: FL03 +*/ +extern crate rstm_core as rstm; + +use rstm::state::{Halt, State}; + +#[test] +fn state() { + // create a new instance of state + let state = State::new(0); + // validate te functional accessors; get and into_inner + assert_eq!(state.get(), &0); + assert_eq!(state.into_inner(), 0); + // create a new mutable instance of state + let mut state = State::new(0); + // replace the inner value with 1 + assert_eq!(state.replace(1), 0); + // verify the replacement + assert_eq!(*state.get(), 1); + // set the inner value to 2 + state.set(2); + // verify the update + assert_eq!(*state.get(), 2); + // reset the state to its default value + state.reset(); + // verify the reset + assert_eq!(*state.get(), 0); + // swap + state.swap(&mut State::new(10)); + // verify the swap + assert_eq!(*state.get(), 10); +} + +#[test] +fn halting() { + // create a new instance of state + let state = Halt::new(0); + // validate te functional accessors; get and into_inner + assert_eq!(state.get(), &0); + assert_eq!(state.into_inner(), 0); + // create a new mutable instance of state + let mut state = Halt::new(0); + // replace the inner value with 1 + assert_eq!(state.replace(1), 0); + // verify the replacement + assert_eq!(*state.get(), 1); + // set the inner value to 2 + state.set(2); + // verify the update + assert_eq!(*state.get(), 2); + // reset the state to its default value + state.reset(); + // verify the reset + assert_eq!(*state.get(), 0); + // swap + state.swap(&mut Halt::new(10)); + // verify the swap + assert_eq!(*state.get(), 10); +} + +#[test] +fn cast_state() { + let q = State(0_isize); + let r = unsafe { q.cast::() }; + assert_eq!(r.get(), &0_usize); +} + +#[test] +fn convert_state() { + let q = State(0_isize); + let r = q.into_any(); + assert_eq!(*r.get().downcast_ref::().unwrap(), 0_isize); +} diff --git a/core/tests/tape.rs b/core/tests/tape.rs new file mode 100644 index 0000000..0af6041 --- /dev/null +++ b/core/tests/tape.rs @@ -0,0 +1,16 @@ +/* + Appellation: tape + Contrib: FL03 +*/ +extern crate rstm_core as rstm; + +use rstm::tape::StdTape; + +#[test] +fn stdtape() { + let mut tape = StdTape::::new(); + tape.write(0); + tape.write(1); + + assert_eq!(tape.read(), Ok(&1)); +} diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index f08bddf..04a2ea1 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -53,11 +53,11 @@ test = true [[example]] name = "actor" -required-features = ["tracing"] +required-features = ["alloc", "tracing"] [[example]] name = "basic" -required-features = ["tracing"] +required-features = ["alloc", "tracing"] # ****************** Dependencies ****************** [dependencies] From c6c782ea2964d0bed27c98c09c6cf88296c76ad3 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Fri, 30 Aug 2024 14:46:00 -0500 Subject: [PATCH 06/27] update Signed-off-by: Joe McCain III --- core/src/actors/mod.rs | 34 +++-- core/src/lib.rs | 2 +- core/src/rules/builders/program.rs | 45 ------- core/src/rules/mod.rs | 12 +- core/src/rules/program.rs | 62 +++++---- core/src/rules/rule.rs | 30 +++++ core/src/types/cursor.rs | 193 ----------------------------- core/src/types/mod.rs | 13 +- core/tests/actor.rs | 11 +- core/tests/rules.rs | 7 +- rstm/examples/actor.rs | 5 +- rstm/examples/basic.rs | 4 +- rstm/src/models/base.rs | 5 +- 13 files changed, 112 insertions(+), 311 deletions(-) delete mode 100644 core/src/rules/builders/program.rs delete mode 100644 core/src/types/cursor.rs diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs index 054328d..1b13ebe 100644 --- a/core/src/actors/mod.rs +++ b/core/src/actors/mod.rs @@ -12,24 +12,44 @@ pub use self::{actor::Actor, exec::Executor}; pub(crate) mod actor; pub(crate) mod exec; +#[allow(unused)] #[doc(hidden)] -pub mod engine; +mod engine; pub(crate) mod prelude { pub use super::actor::Actor; pub use super::exec::Executor; } -use crate::{rules::Program, Alphabet}; +pub trait Program { + fn get(&self, state: crate::State<&Q>, symbol: &S) -> Option<&crate::Rule>; -#[doc(hidden)] -pub trait Model { - type Alpha: Alphabet; + fn get_mut(&mut self, state: crate::State<&Q>, symbol: &S) -> Option<&mut crate::Rule>; } #[doc(hidden)] pub trait Runtime { - fn load(&mut self, program: Program); + fn load(&mut self, program: I) + where + I: IntoIterator>; + + fn run(&mut self) -> Result<(), crate::Error>; +} + +impl Runtime for Executor +where + Q: Clone + PartialEq + 'static, + S: crate::Symbolic, +{ + fn load(&mut self, program: I) + where + I: IntoIterator>, + { + self.program.rules.clear(); + self.program.extend(program); + } - fn run(&mut self); + fn run(&mut self) -> Result<(), crate::Error> { + Executor::run(self) + } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 5819240..a96c0a8 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -46,10 +46,10 @@ pub(crate) mod macros { #[macro_use] pub(crate) mod seal; -#[doc(hidden)] pub mod actors; pub mod error; pub mod rules; +#[doc(hidden)] pub mod shift; pub mod state; pub mod tape; diff --git a/core/src/rules/builders/program.rs b/core/src/rules/builders/program.rs deleted file mode 100644 index ecbfc07..0000000 --- a/core/src/rules/builders/program.rs +++ /dev/null @@ -1,45 +0,0 @@ -/* - Appellation: builder - Contrib: FL03 -*/ -use crate::rules::{Program, Rule}; -use crate::State; - -#[derive(Default)] -pub struct ProgramBuilder { - initial_state: Option>, - rules: Vec>, -} - -impl ProgramBuilder { - pub fn new() -> Self { - Self { - initial_state: None, - rules: Vec::new(), - } - } - - pub fn initial_state(self, State(state): State) -> Self { - Self { - initial_state: Some(State(state)), - ..self - } - } - - pub fn rules(self, rules: I) -> Self - where - I: IntoIterator>, - { - Self { - rules: Vec::from_iter(rules), - ..self - } - } - - pub fn build(self) -> Program { - Program { - initial_state: self.initial_state.unwrap(), - rules: self.rules, - } - } -} diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index 172dbbf..213828d 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -3,22 +3,16 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{ - builders::{ProgramBuilder, RuleBuilder}, - program::Program, - rule::Rule, - ruleset::RuleSet, -}; +pub use self::{builders::RuleBuilder, program::Program, rule::Rule, ruleset::RuleSet}; pub(crate) mod program; pub(crate) mod rule; pub mod ruleset; #[doc(hidden)] -pub(crate) mod builders { - pub use self::{program::ProgramBuilder, rule::RuleBuilder}; +mod builders { + pub use self::rule::RuleBuilder; - mod program; mod rule; } diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index d0f802f..4d9cdfb 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -2,70 +2,81 @@ Appellation: program Contrib: FL03 */ -use super::{ProgramBuilder, Rule}; +#![cfg(feature = "alloc")] +use super::Rule; use crate::{Head, State, Tail}; -use std::vec; +use alloc::vec::{self, Vec}; type Ruleset = Vec>; - #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Program { - pub(crate) initial_state: State, - pub(crate) rules: Ruleset, + pub(crate) initial_state: Option>, + pub(crate) rules: Vec>, } impl Program { - pub fn new() -> ProgramBuilder { - ProgramBuilder::new() + pub fn new() -> Self { + Self { + initial_state: None, + rules: Vec::new(), + } } - pub fn from_iter(instructions: impl IntoIterator>) -> Self + pub fn from_iter(iter: I) -> Self where - Q: Default, + I: IntoIterator>, { Self { - initial_state: State::default(), - rules: Ruleset::from_iter(instructions), + initial_state: None, + rules: Vec::from_iter(iter), } } - pub fn from_state(State(initial_state): State) -> Self { + pub fn from_state(initial_state: State) -> Self { Self { - initial_state: State(initial_state), - rules: Ruleset::new(), + initial_state: Some(initial_state), + rules: Vec::new(), } } - /// - pub fn with_initial_state(self, State(state): State) -> Self { + + pub fn with_initial_state(self, state: State) -> Self { Self { - initial_state: State(state), + initial_state: Some(state), ..self } } - /// - pub fn with_instructions(self, instructions: impl IntoIterator>) -> Self { + + pub fn with_rules(self, instructions: I) -> Self + where + I: IntoIterator>, + { Self { - rules: Ruleset::from_iter(instructions), + rules: Vec::from_iter(instructions), ..self } } + /// Returns an owned reference to the initial state of the program. - pub fn initial_state(&self) -> State<&'_ Q> { - self.initial_state.to_ref() + pub fn initial_state(&self) -> Option> { + self.initial_state.as_ref().map(|state| state.to_ref()) } + /// Returns a reference to the instructions. pub const fn instructions(&self) -> &Ruleset { &self.rules } + /// Returns a mutable reference to the instructions. pub fn instructions_mut(&mut self) -> &mut Ruleset { &mut self.rules } + /// Returns an iterator over the elements. pub fn iter(&self) -> core::slice::Iter> { self.rules.iter() } + /// Returns a mutable iterator over the elements. pub fn iter_mut(&mut self) -> core::slice::IterMut> { self.rules.iter_mut() @@ -84,6 +95,7 @@ impl Program { } }) } + /// Returns a collection of tails for a given head. pub fn get_head(&self, head: &Head) -> Option<&Tail> where @@ -98,6 +110,7 @@ impl Program { } }) } + /// Returns a mutable collection of tails for a given head. pub fn get_mut(&mut self, head: &Head) -> Option<&mut Tail> where @@ -112,6 +125,7 @@ impl Program { } }) } + /// Returns a collection of tails for a given head. pub fn get_ref(&self, head: Head<&'_ Q, &'_ S>) -> Option> where @@ -169,7 +183,7 @@ where impl From> for Program { fn from(instructions: Ruleset) -> Self { Self { - initial_state: State::default(), + initial_state: Some(State::default()), rules: instructions, } } @@ -187,7 +201,7 @@ where { fn from_iter>>(iter: I) -> Self { Self { - initial_state: State::default(), + initial_state: Some(State::default()), rules: Ruleset::from_iter(iter), } } diff --git a/core/src/rules/rule.rs b/core/src/rules/rule.rs index 289a39b..da6b877 100644 --- a/core/src/rules/rule.rs +++ b/core/src/rules/rule.rs @@ -147,6 +147,36 @@ impl core::borrow::BorrowMut> for Rule { } } +impl PartialEq<(Head, Tail)> for Rule +where + Q: PartialEq, + S: PartialEq, +{ + fn eq(&self, other: &(Head, Tail)) -> bool { + &self.head == &other.0 && &self.tail == &other.1 + } +} + +impl PartialEq> for Rule +where + Q: PartialEq, + S: PartialEq, +{ + fn eq(&self, other: &Head) -> bool { + &self.head == other + } +} + +impl PartialEq> for Rule +where + Q: PartialEq, + S: PartialEq, +{ + fn eq(&self, other: &Tail) -> bool { + &self.tail == other + } +} + impl From<(Head, Tail)> for Rule { fn from((head, tail): (Head, Tail)) -> Self { Self { head, tail } diff --git a/core/src/types/cursor.rs b/core/src/types/cursor.rs deleted file mode 100644 index de47332..0000000 --- a/core/src/types/cursor.rs +++ /dev/null @@ -1,193 +0,0 @@ -/* - Appellation: cursor - Contrib: FL03 -*/ -use crate::Direction; - -/// Here, [Cursor] describes a type capable of tracking both the position and number of steps -/// taken by an actor. -#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Cursor { - /// The current position of the cursor. - pub(crate) position: Idx, - /// The number of steps taken by the cursor. - pub(crate) ticks: usize, -} - -impl Cursor { - pub fn new() -> Cursor - where - Idx: Default, - { - Cursor { - position: Idx::default(), - ticks: 0, - } - } - /// Resets the cursor to its initial state. - pub fn reset(&mut self) - where - Idx: Default, - { - self.position = Idx::default(); - self.ticks = 0; - } - /// Returns the current position of the cursor. - pub const fn position(&self) -> &Idx { - &self.position - } - - pub fn ticks(&self) -> usize { - self.ticks - } - - pub fn set_position(&mut self, position: Idx) { - self.position = position; - self.on_update() - } - /// Shifts the cursor in the given direction. - pub fn shift(&mut self, direction: Direction) - where - Idx: core::ops::AddAssign, - { - self.position += direction; - self.on_update() - } - - pub fn shift_left(&mut self) - where - Idx: core::ops::AddAssign, - { - self.shift(Direction::Left) - } - - pub fn shift_right(&mut self) - where - Idx: core::ops::AddAssign, - { - self.shift(Direction::Right) - } - - pub fn stay(&mut self) { - self.on_update() - } - - pub(crate) fn on_update(&mut self) { - self.ticks += 1; - } -} - -#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Ticker { - pub(crate) ticks: T, -} - -impl Ticker { - pub fn new() -> Self - where - T: Default, - { - Self { - ticks: T::default(), - } - } - - pub const fn get(&self) -> &T { - &self.ticks - } - - pub fn reset(&mut self) - where - T: Default, - { - self.ticks = T::default(); - } - - pub fn set(&mut self, ticks: T) { - self.ticks = ticks; - } - - pub fn tick(&mut self) - where - T: core::ops::AddAssign + num::One, - { - self.ticks += T::one(); - } -} - -impl core::convert::AsRef for Ticker { - fn as_ref(&self) -> &T { - &self.ticks - } -} - -impl core::convert::AsMut for Ticker { - fn as_mut(&mut self) -> &mut T { - &mut self.ticks - } -} - -impl core::ops::Deref for Ticker { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.ticks - } -} - -impl core::ops::DerefMut for Ticker { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.ticks - } -} - -impl core::iter::Iterator for Ticker -where - T: Copy + core::ops::AddAssign + num::One, -{ - type Item = T; - - fn next(&mut self) -> Option { - self.tick(); - Some(self.ticks) - } -} - -impl core::cmp::PartialEq for Ticker -where - T: PartialEq, -{ - fn eq(&self, other: &T) -> bool { - &self.ticks == other - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_cursor() { - let mut cursor = Cursor::::new(); - assert_eq!(*cursor.position(), 0); - assert_eq!(cursor.ticks(), 0); - - cursor.shift(Direction::Right); - assert_eq!(*cursor.position(), 1); - assert_eq!(cursor.ticks(), 1); - - cursor.shift(Direction::Left); - assert_eq!(*cursor.position(), 0); - assert_eq!(cursor.ticks(), 2); - - cursor.shift(Direction::Stay); - assert_eq!(*cursor.position(), 0); - assert_eq!(cursor.ticks(), 3); - - cursor.set_position(10); - assert_eq!(*cursor.position(), 10); - assert_eq!(cursor.ticks(), 4); - } -} diff --git a/core/src/types/mod.rs b/core/src/types/mod.rs index 7ebdaa1..0dfc9cc 100644 --- a/core/src/types/mod.rs +++ b/core/src/types/mod.rs @@ -9,20 +9,11 @@ pub(crate) mod direction; pub(crate) mod head; pub(crate) mod tail; -#[doc(hidden)] -pub mod cursor; - pub(crate) mod prelude { pub use super::direction::*; pub use super::head::Head; pub use super::tail::Tail; - pub use super::IndexedHead; - - #[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; -/// A type alias for a head which store an index as its symbol -pub type IndexedHead = Head; +/// A type alias for a [Result] with our custom error type: [`Error`](crate::Error) +pub type Result = core::result::Result; diff --git a/core/tests/actor.rs b/core/tests/actor.rs index 8742ef4..2e5a365 100644 --- a/core/tests/actor.rs +++ b/core/tests/actor.rs @@ -8,8 +8,6 @@ use rstm::actors::Actor; use rstm::rules::{Program, Rule}; use rstm::{ruleset, State}; -const INITIAL_STATE: State = State(0); - lazy_static::lazy_static! { static ref RULES: [Rule; 6] = ruleset![ (0, 0) -> Right(1, 1), @@ -20,19 +18,16 @@ lazy_static::lazy_static! { (-1, 1) -> Left(0, 1), ]; - static ref PROGRAM: Program = Program::from_iter(RULES.clone()).with_initial_state(INITIAL_STATE); } #[test] fn busy_beaver() { + let initial_state = State(0_isize); let input = [0_usize; 10]; - let program = Program::new() - .rules(RULES.clone()) - .initial_state(INITIAL_STATE) - .build(); + let program = Program::from_iter(RULES.clone()); - let actor = Actor::from_state(State(0)).with_tape(input); + let actor = Actor::from_state(initial_state).with_tape(input); let mut rt = actor.execute(program); for _ in 0..10 { assert!(rt.next().is_some()); diff --git a/core/tests/rules.rs b/core/tests/rules.rs index 3856338..d46836d 100644 --- a/core/tests/rules.rs +++ b/core/tests/rules.rs @@ -20,14 +20,9 @@ fn ruleset() { // validate the number of rules within the ruleset assert_eq!(rules.len(), 6); // create a new program using the ruleset - let program = Program::new() - .initial_state(State(0isize)) - .rules(rules) - .build(); + let program = Program::from_iter(rules); // validate the number of rules within the program assert_eq!(rules.len(), program.len()); - // compare the inner value of the initial state - assert_eq!(program.initial_state(), &0); // create a new head for a rule within the program let head = Head::new(State(0), 0); // retrieve and validate the tail for the given head diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index 5e53b2e..cd19098 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -22,10 +22,7 @@ fn main() -> Result<(), Box> { (-1, 1) -> Left(1, 1), ]; - let program = Program::new() - .initial_state(initial_state) - .rules(rules) - .build(); + let program = Program::from_iter(rules); // create a new instance of the machine let tm = dbg!(Actor::from_state(initial_state).with_tape(alpha)); diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index c6a243d..44d9f2c 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -4,7 +4,7 @@ */ extern crate rstm; -use rstm::{ruleset, Program, State, StdTM, StdTape}; +use rstm::{ruleset, Program, StdTM, StdTape}; fn main() -> Result<(), Box> { _tracing("debug"); @@ -21,7 +21,7 @@ fn main() -> Result<(), Box> { (-1, 1) -> Left(1, 1), ]; // create a new program with the rules - let program = Program::new().initial_state(State(0)).rules(rules).build(); + let program = Program::from_iter(rules); // create a new tape with the data let tape = StdTape::from_iter(alpha); // create a new instance of the machine diff --git a/rstm/src/models/base.rs b/rstm/src/models/base.rs index ab852fa..1fae950 100644 --- a/rstm/src/models/base.rs +++ b/rstm/src/models/base.rs @@ -26,7 +26,10 @@ impl StdTM { Q: Clone + Default, S: Default, { - let state = program.initial_state().cloned(); + let state = program + .initial_state() + .map(|q| q.cloned()) + .unwrap_or_default(); StdTM { program, state: HaltState::state(state), From 65516a6bb4c33e5b6b4a04145ac4cffd3de1bbb5 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sat, 31 Aug 2024 06:29:55 -0500 Subject: [PATCH 07/27] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 44 ++++++++++++++++++++++++------------ core/tests/actor.rs | 2 +- rstm/Cargo.toml | 4 ---- rstm/examples/actor.rs | 24 ++++++++++---------- rstm/examples/basic.rs | 48 ---------------------------------------- 5 files changed, 43 insertions(+), 79 deletions(-) delete mode 100644 rstm/examples/basic.rs diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index e0f6cb9..9d34270 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -35,8 +35,8 @@ impl Actor { }, } } - - pub fn with_tape(self, alpha: I) -> Self + /// Consumes the current instance and returns a new instance with the given alphabet + pub fn with_alpha(self, alpha: I) -> Self where I: IntoIterator, { @@ -45,6 +45,30 @@ impl Actor { ..self } } + /// Consumes the current instance and returns a new instance with the given head + pub fn with_head(self, head: Head) -> Self { + Self { head, ..self } + } + /// Consumes the current instance and returns a new instance with the given position + pub fn with_position(self, symbol: usize) -> Self { + Self { + head: Head { + state: self.head.state, + symbol, + }, + ..self + } + } + /// Consumes the current instance and returns a new instance with the given state + pub fn with_state(self, State(state): State) -> Self { + Self { + head: Head { + state: State(state), + symbol: self.head.symbol, + }, + ..self + } + } /// Returns an immutable reference to the tape alphabet as a slice pub fn alpha(&self) -> &[S] { &self.alpha @@ -65,6 +89,10 @@ impl Actor { symbol: self.head.symbol, } } + /// Returns the current position of the head on the tape + pub fn position(&self) -> usize { + self.head.symbol + } /// Returns an instance of the state with an immutable reference to the inner value pub fn state(&self) -> State<&Q> { self.head.state() @@ -78,14 +106,6 @@ impl Actor { pub fn execute(self, program: Program) -> Executor { Executor::new(self, program) } - /// Reads the current symbol at the head of the tape - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, name = "get", target = "actor") - )] - pub fn get(&self) -> Option<&S> { - self.alpha().get(self.position()) - } /// Checks if the tape is empty pub fn is_empty(&self) -> bool { self.alpha.is_empty() @@ -102,10 +122,6 @@ impl Actor { pub fn len(&self) -> usize { self.alpha.len() } - /// Returns the current position of the head on the tape - pub fn position(&self) -> usize { - self.head.symbol - } /// Reads the current symbol at the head of the tape #[cfg_attr( feature = "tracing", diff --git a/core/tests/actor.rs b/core/tests/actor.rs index 2e5a365..3f2bc54 100644 --- a/core/tests/actor.rs +++ b/core/tests/actor.rs @@ -27,7 +27,7 @@ fn busy_beaver() { let program = Program::from_iter(RULES.clone()); - let actor = Actor::from_state(initial_state).with_tape(input); + let actor = Actor::from_state(initial_state).with_alpha(input); let mut rt = actor.execute(program); for _ in 0..10 { assert!(rt.next().is_some()); diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index 04a2ea1..02af905 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -55,10 +55,6 @@ test = true name = "actor" required-features = ["alloc", "tracing"] -[[example]] -name = "basic" -required-features = ["alloc", "tracing"] - # ****************** Dependencies ****************** [dependencies] thiserror.workspace = true diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index cd19098..2bb6fe6 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -7,7 +7,7 @@ extern crate rstm; use rstm::{ruleset, Actor, Program, State}; fn main() -> Result<(), Box> { - _tracing(); + _tracing("debug"); // initialize the tape data let alpha = vec![0u8; 10]; // initialize the state of the machine @@ -25,25 +25,25 @@ fn main() -> Result<(), Box> { let program = Program::from_iter(rules); // create a new instance of the machine - let tm = dbg!(Actor::from_state(initial_state).with_tape(alpha)); + let tm = dbg!(Actor::from_state(initial_state).with_alpha(alpha)); tm.execute(program).run()?; Ok(()) } -fn _tracing() { + +fn _tracing(level: &str) { + let level = match level { + "debug" => tracing::Level::DEBUG, + "error" => tracing::Level::ERROR, + "trace" => tracing::Level::TRACE, + "warn" => tracing::Level::WARN, + _ => tracing::Level::INFO, + }; let timer = tracing_subscriber::fmt::time::uptime(); tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) + .with_max_level(level) .with_target(false) .with_timer(timer) .init(); tracing::info!("Welcome to rstm!"); } - -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub enum S3 { - A = 0, - B = 1, - C = -1, -} diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs deleted file mode 100644 index 44d9f2c..0000000 --- a/rstm/examples/basic.rs +++ /dev/null @@ -1,48 +0,0 @@ -/* - Appellation: default - Contrib: FL03 -*/ -extern crate rstm; - -use rstm::{ruleset, Program, StdTM, StdTape}; - -fn main() -> Result<(), Box> { - _tracing("debug"); - - // initialize the tape data - let alpha = [0_usize; 10]; - // define the rules for the machine - let rules = ruleset![ - (0, 0) -> Right(1, 0), - (0, 1) -> Right(-1, 1), - (1, 0) -> Right(0, 1), - (1, 1) -> Right(-1, 0), - (-1, 0) -> Left(0, 0), - (-1, 1) -> Left(1, 1), - ]; - // create a new program with the rules - let program = Program::from_iter(rules); - // create a new tape with the data - let tape = StdTape::from_iter(alpha); - // create a new instance of the machine - let tm = StdTM::new(program, tape); - tm.execute()?; - Ok(()) -} - -fn _tracing(level: &str) { - let level = match level { - "debug" => tracing::Level::DEBUG, - "error" => tracing::Level::ERROR, - "trace" => tracing::Level::TRACE, - "warn" => tracing::Level::WARN, - _ => tracing::Level::INFO, - }; - let timer = tracing_subscriber::fmt::time::uptime(); - tracing_subscriber::fmt() - .with_max_level(level) - .with_target(false) - .with_timer(timer) - .init(); - tracing::info!("Welcome to rstm!"); -} From 0938c3df3594fb940e0ba88fe7be5da5853688c5 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sat, 31 Aug 2024 06:44:47 -0500 Subject: [PATCH 08/27] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 82 ++++------------------------------------ rstm/examples/actor.rs | 5 +-- 2 files changed, 10 insertions(+), 77 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 9d34270..b1a9974 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -2,9 +2,6 @@ Appellation: actor Contrib: FL03 */ -#[doc(inline)] -pub use self::builder::ActorBuilder; - use super::Executor; use crate::rules::Program; use crate::{Direction, Error, Head, State, Tail}; @@ -21,8 +18,14 @@ pub struct Actor { } impl Actor { - pub fn new() -> ActorBuilder { - ActorBuilder::new() + pub fn new(alpha: impl IntoIterator, State(state): State, symbol: usize) -> Self { + Self { + alpha: Vec::from_iter(alpha), + head: Head { + state: State(state), + symbol, + }, + } } /// Constructs a new [Actor] with the given state; assumes the tape is empty and the head /// is located at `0`. @@ -214,72 +217,3 @@ where Ok(()) } } - -mod builder { - use super::*; - use core::iter::FromIterator; - - #[derive(Default)] - pub struct ActorBuilder { - alpha: Vec, - state: Option>, - symbol: usize, - } - - impl ActorBuilder { - pub(crate) fn new() -> Self { - Self { - alpha: Vec::new(), - state: None, - symbol: 0, - } - } - - pub fn alpha(self, alpha: I) -> Self - where - I: IntoIterator, - { - Self { - alpha: Vec::from_iter(alpha), - ..self - } - } - - pub fn head(self, head: Head) -> Self { - Self { - state: Some(head.state), - symbol: head.symbol, - ..self - } - } - - pub fn state(self, State(state): State) -> Self { - Self { - state: Some(State(state)), - ..self - } - } - - pub fn position(self, symbol: usize) -> Self { - Self { symbol, ..self } - } - - pub fn build(self) -> Actor - where - Q: Default, - { - let ActorBuilder { - alpha, - state, - symbol, - } = self; - Actor { - alpha, - head: Head { - state: state.unwrap_or_default(), - symbol, - }, - } - } - } -} diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index 2bb6fe6..d3d850d 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -21,11 +21,10 @@ fn main() -> Result<(), Box> { (-1, 0) -> Left(0, 0), (-1, 1) -> Left(1, 1), ]; - + // create a new program from the ruleset let program = Program::from_iter(rules); - // create a new instance of the machine - let tm = dbg!(Actor::from_state(initial_state).with_alpha(alpha)); + let tm = dbg!(Actor::new(alpha, initial_state, 0)); tm.execute(program).run()?; Ok(()) } From 6c8c5070f84fb77c955c80389e0005b6e305905d Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sat, 31 Aug 2024 06:44:57 -0500 Subject: [PATCH 09/27] update Signed-off-by: Joe McCain III --- rstm/examples/actor.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index d3d850d..4584ba7 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -29,7 +29,6 @@ fn main() -> Result<(), Box> { Ok(()) } - fn _tracing(level: &str) { let level = match level { "debug" => tracing::Level::DEBUG, From c45821ff7bdbd86954da81f1251ca82199da593b Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sat, 31 Aug 2024 06:45:15 -0500 Subject: [PATCH 10/27] update Signed-off-by: Joe McCain III --- core/src/rules/builders/instructions.rs | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 core/src/rules/builders/instructions.rs diff --git a/core/src/rules/builders/instructions.rs b/core/src/rules/builders/instructions.rs deleted file mode 100644 index 4ebe5fc..0000000 --- a/core/src/rules/builders/instructions.rs +++ /dev/null @@ -1,13 +0,0 @@ -/* - Appellation: instructions - Contrib: FL03 -*/ -use crate::{Head, State, Tail}; -use std::collections::HashMap; - - -#[derive(Default)] -pub struct RulesetBuilder { - pub(crate) initial_state: Option>, - pub(crate) rules: HashMap, Tail>, -} \ No newline at end of file From bde4f3a86419759475247e581e6b65cc13974da6 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sat, 31 Aug 2024 13:24:26 -0500 Subject: [PATCH 11/27] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 51 ++++++++--------- core/src/rules/program.rs | 61 ++++++++++---------- core/src/state/halt/mod.rs | 72 +++++++++++++++++++++-- core/src/state/halt/state.rs | 2 +- core/src/state/halt/wrap.rs | 2 +- core/src/state/mod.rs | 51 ++++++++--------- core/src/state/state.rs | 72 +++++++++++------------ core/src/types/direction.rs | 83 +++++++++++++++++---------- core/src/types/head.rs | 108 ++++++++++++++++++++++++++++++----- core/tests/rules.rs | 2 +- core/tests/state.rs | 16 +++--- rstm/src/models/base.rs | 5 +- 12 files changed, 344 insertions(+), 181 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index b1a9974..4a1ae2f 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -18,24 +18,18 @@ pub struct Actor { } impl Actor { - pub fn new(alpha: impl IntoIterator, State(state): State, symbol: usize) -> Self { + pub fn new(alpha: impl IntoIterator, state: State, symbol: usize) -> Self { Self { alpha: Vec::from_iter(alpha), - head: Head { - state: State(state), - symbol, - }, + head: Head { state, symbol }, } } /// Constructs a new [Actor] with the given state; assumes the tape is empty and the head /// is located at `0`. - pub fn from_state(State(state): State) -> Self { + pub fn from_state(state: State) -> Self { Self { alpha: Vec::new(), - head: Head { - state: State(state), - symbol: 0, - }, + head: Head { state, symbol: 0 }, } } /// Consumes the current instance and returns a new instance with the given alphabet @@ -56,26 +50,27 @@ impl Actor { pub fn with_position(self, symbol: usize) -> Self { Self { head: Head { - state: self.head.state, symbol, + ..self.head }, ..self } } /// Consumes the current instance and returns a new instance with the given state - pub fn with_state(self, State(state): State) -> Self { + pub fn with_state(self, state: State) -> Self { Self { - head: Head { - state: State(state), - symbol: self.head.symbol, - }, + head: Head { state, ..self.head }, ..self } } - /// Returns an immutable reference to the tape alphabet as a slice + /// Returns an immutable reference to the tape, as a slice pub fn alpha(&self) -> &[S] { &self.alpha } + /// Returns a mutable reference of the tape as a slice + pub fn alpha_mut(&mut self) -> &mut [S] { + &mut self.alpha + } /// Returns an immutable reference to the head of the tape pub const fn head(&self) -> &Head { &self.head @@ -118,7 +113,7 @@ impl Actor { where Q: 'static, { - self.head.state.is_halt() + self.head().state.is_halt() } /// Returns the length of the tape #[inline] @@ -155,6 +150,8 @@ impl Actor { if pos == usize::MAX { #[cfg(feature = "tracing")] tracing::trace!("Prepending to the tape..."); + // prepend to the tape + self.alpha.insert(0, value); } else if pos >= self.len() { #[cfg(feature = "tracing")] tracing::trace!("Appending to the tape..."); @@ -164,25 +161,27 @@ impl Actor { self.alpha[pos] = value; } } - /// Performs a single step of the Turing machine + /// Performs a single step of the Turing machine; returns the previous head of the tape #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "handle", target = "actor") )] - pub(crate) fn handle(&mut self, direction: Direction, State(state): State, symbol: S) { + pub(crate) fn handle( + &mut self, + direction: Direction, + state: State, + symbol: S, + ) -> Head { #[cfg(feature = "tracing")] tracing::trace!("Transitioning the actor..."); // write the symbol to the tape self.write(symbol); // update the head of the actor - self.head = Head { - state: State(state), - symbol: direction.apply_unsigned(self.head.symbol), - }; + self.head.replace(state, self.position() + direction) } - pub(crate) fn process(&mut self, rule: Tail) { - self.handle(rule.direction, rule.state, rule.symbol); + pub(crate) fn process(&mut self, rule: Tail) -> Head { + self.handle(rule.direction, rule.state, rule.symbol) } } diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index 4d9cdfb..ab41386 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -7,12 +7,13 @@ use super::Rule; use crate::{Head, State, Tail}; use alloc::vec::{self, Vec}; -type Ruleset = Vec>; +type Rules = Vec>; + #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Program { pub(crate) initial_state: Option>, - pub(crate) rules: Vec>, + pub(crate) rules: Rules, } impl Program { @@ -22,7 +23,7 @@ impl Program { rules: Vec::new(), } } - + /// Create a new instance of the [Program] from the given rules. pub fn from_iter(iter: I) -> Self where I: IntoIterator>, @@ -32,21 +33,21 @@ impl Program { rules: Vec::from_iter(iter), } } - + /// Create a new instance of the [Program] using the given initial state. pub fn from_state(initial_state: State) -> Self { Self { initial_state: Some(initial_state), rules: Vec::new(), } } - + /// Configures the program to use the given initial state. pub fn with_initial_state(self, state: State) -> Self { Self { initial_state: Some(state), ..self } } - + /// Configures the program with the given rules; pub fn with_rules(self, instructions: I) -> Self where I: IntoIterator>, @@ -56,32 +57,27 @@ impl Program { ..self } } - /// Returns an owned reference to the initial state of the program. pub fn initial_state(&self) -> Option> { self.initial_state.as_ref().map(|state| state.to_ref()) } - /// Returns a reference to the instructions. - pub const fn instructions(&self) -> &Ruleset { + pub const fn instructions(&self) -> &Rules { &self.rules } - /// Returns a mutable reference to the instructions. - pub fn instructions_mut(&mut self) -> &mut Ruleset { + pub fn instructions_mut(&mut self) -> &mut Rules { &mut self.rules } - /// Returns an iterator over the elements. pub fn iter(&self) -> core::slice::Iter> { self.rules.iter() } - /// Returns a mutable iterator over the elements. pub fn iter_mut(&mut self) -> core::slice::IterMut> { self.rules.iter_mut() } - + /// Returns a collection of tails for a given head. pub fn get(&self, State(state): State<&Q>, symbol: &S) -> Option<&Tail> where Q: PartialEq, @@ -95,37 +91,34 @@ impl Program { } }) } - - /// Returns a collection of tails for a given head. - pub fn get_head(&self, head: &Head) -> Option<&Tail> + /// Returns a mutable reference to a the tail matching the given head. + pub fn get_mut(&mut self, State(state): State<&Q>, symbol: &S) -> Option<&mut Tail> where Q: PartialEq, S: PartialEq, { - self.iter().find_map(|i| { - if i.head() == head { - Some(i.tail()) + self.iter_mut().find_map(|i| { + if i.head().state() == state && i.head().symbol() == symbol { + Some(i.tail_mut()) } else { None } }) } - - /// Returns a mutable collection of tails for a given head. - pub fn get_mut(&mut self, head: &Head) -> Option<&mut Tail> + /// Returns a collection of tails for a given head. + pub fn get_by_head(&self, head: &Head) -> Option<&Tail> where Q: PartialEq, S: PartialEq, { - self.iter_mut().find_map(|i| { + self.iter().find_map(|i| { if i.head() == head { - Some(i.tail_mut()) + Some(i.tail()) } else { None } }) } - /// Returns a collection of tails for a given head. pub fn get_ref(&self, head: Head<&'_ Q, &'_ S>) -> Option> where @@ -140,6 +133,14 @@ impl Program { } }) } + /// Returns a collection of rules whose head contains a match for the given state. + pub fn filter_by_state(&self, state: State<&Q>) -> Vec<&Rule> + where + Q: PartialEq, + S: PartialEq, + { + self.iter().filter(|i| *i.head() == state).collect() + } } impl AsRef<[Rule]> for Program { @@ -176,12 +177,12 @@ where type Output = Tail; fn index(&self, index: Head) -> &Self::Output { - self.get_head(&index).unwrap() + self.get_by_head(&index).unwrap() } } -impl From> for Program { - fn from(instructions: Ruleset) -> Self { +impl From> for Program { + fn from(instructions: Rules) -> Self { Self { initial_state: Some(State::default()), rules: instructions, @@ -202,7 +203,7 @@ where fn from_iter>>(iter: I) -> Self { Self { initial_state: Some(State::default()), - rules: Ruleset::from_iter(iter), + rules: Rules::from_iter(iter), } } } diff --git a/core/src/state/halt/mod.rs b/core/src/state/halt/mod.rs index 6c0b9d0..52554a6 100644 --- a/core/src/state/halt/mod.rs +++ b/core/src/state/halt/mod.rs @@ -2,8 +2,10 @@ Appellation: halt Contrib: FL03 */ -//! This module is responsible for defining the [Halt] state of a Turing machine. +//! # Halting State //! +//! For all intents and purposes, the halt state is an imaginary state not actually considered +//! by the machine's state space. //! #[doc(inline)] pub use self::{state::Halt, wrap::HaltState}; @@ -15,11 +17,26 @@ use super::RawState; #[doc(hidden)] pub trait Haltable { - const HALT: bool = true; - - type State: RawState; + type State: RawState; private!(); + + fn is_halted(&self) -> bool; +} + +#[doc(hidden)] +pub trait HaltableExt: Haltable { + fn get(self) -> Option; + + fn get_mut(&mut self) -> Option<&mut Q>; + + fn map(self, f: F) -> Option + where + F: FnOnce(Q) -> U, + Self: Sized, + { + self.get().map(|state| f(state)) + } } /* @@ -31,10 +48,57 @@ impl Haltable for Halt { type State = State; seal!(); + + fn is_halted(&self) -> bool { + true + } } impl Haltable for State> { type State = State; seal!(); + + fn is_halted(&self) -> bool { + true + } +} +impl Haltable for State> { + type State = State; + + seal!(); + + fn is_halted(&self) -> bool { + self.get_ref().is_none() + } +} + +impl Haltable for Option> { + type State = State; + + seal!(); + + fn is_halted(&self) -> bool { + self.is_none() + } +} + +impl HaltableExt for Option> { + fn get(self) -> Option { + self.map(|state| state.get()) + } + + fn get_mut(&mut self) -> Option<&mut Q> { + self.as_mut().map(|state| state.get_mut()) + } +} + +impl HaltableExt for State> { + fn get(self) -> Option { + self.get() + } + + fn get_mut(&mut self) -> Option<&mut Q> { + self.get_mut().as_mut() + } } diff --git a/core/src/state/halt/state.rs b/core/src/state/halt/state.rs index 35e2eb3..d03825d 100644 --- a/core/src/state/halt/state.rs +++ b/core/src/state/halt/state.rs @@ -43,7 +43,7 @@ impl Halt { /// Swaps the inner value of the halted state with that of the given state. pub fn swap(&mut self, other: &mut S) where - S: RawState, + S: RawState, { core::mem::swap(&mut self.0, other.get_mut()); } diff --git a/core/src/state/halt/wrap.rs b/core/src/state/halt/wrap.rs index f643151..e4fefb2 100644 --- a/core/src/state/halt/wrap.rs +++ b/core/src/state/halt/wrap.rs @@ -56,7 +56,7 @@ impl HaltState { pub fn get(&self) -> &Q { match self { - Self::State(inner) => inner.get(), + Self::State(inner) => inner.get_ref(), Self::Halt(inner) => inner.get(), } } diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index 47a7a56..90b6ee8 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -17,63 +17,70 @@ pub(crate) mod states { } pub(crate) mod prelude { - pub use super::halt::*; + pub use super::halt::Haltable; pub use super::state::State; pub use super::states::*; pub use super::AnyState; } - +/// A type alias for a [State] whose inner value is the dynamically sized type of a boxed [`Any`](core::any::Any). pub type AnyState = State>; /// [RawState] is a trait describing objects capable of being used as states in our library. /// The trait contains a single associated trait, the context, or inner value of the state. #[doc(hidden)] pub trait RawState { - type Inner; + type Q; private!(); - fn into_inner(self) -> Self::Inner; + fn into_inner(self) -> Self::Q; - fn get(&self) -> &Self::Inner; + fn get(&self) -> &Self::Q; - fn get_mut(&mut self) -> &mut Self::Inner; + fn get_mut(&mut self) -> &mut Self::Q; - fn set(&mut self, inner: Self::Inner); + fn set(&mut self, inner: Self::Q); } #[doc(hidden)] pub trait Stateful { - type State: RawState; -} + type State: RawState; + + fn get(self) -> Q; + + fn get_mut(&mut self) -> &mut Q; + + fn set(&mut self, state: Q); -pub trait StatefulView: Stateful { - fn state(&self) -> &Self::State; + fn map(self, f: F) -> Option + where + F: FnOnce(Q) -> U, + Self: Sized; } /* ************* Implementations ************* */ macro_rules! impl_raw_state { - (@impl $T:ident($($field:tt)*)) => { - impl RawState for $T { - type Inner = Q; + (@impl $state:ident($($field:tt)*)) => { + impl RawState for $state { + type Q = Q; seal!(); - fn into_inner(self) -> Self::Inner { + fn into_inner(self) -> Q { self.$($field)* } - fn get(&self) -> &Self::Inner { + fn get(&self) -> &Q { &self.$($field)* } - fn get_mut(&mut self) -> &mut Self::Inner { + fn get_mut(&mut self) -> &mut Q { &mut self.$($field)* } - fn set(&mut self, inner: Self::Inner) { + fn set(&mut self, inner: Q) { self.$($field)* = inner; } } @@ -89,11 +96,3 @@ impl_raw_state! { Halt(0), State(0), } - -impl Stateful for Halt { - type State = State; -} - -impl Stateful for State { - type State = State; -} diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 17ee038..80287ee 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -23,39 +23,27 @@ impl State { pub unsafe fn cast(self) -> State { State(core::ptr::read(&self.0 as *const Q as *const R)) } - /// Returns an immutable reference to the state. - pub const fn get(&self) -> &Q { - &self.0 - } - /// Returns a mutable reference to the state. - pub fn get_mut(&mut self) -> &mut Q { - &mut self.0 - } + #[inline] /// Consumes and returns the inner value of the state. - pub fn into_inner(self) -> Q { + pub fn get(self) -> Q { 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(&Q) -> R, - { - State(f(self.get())) + /// Returns an immutable reference to the inner value of the state. + pub const fn get_ref(&self) -> &Q { + &self.0 } - /// [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.get_mut())) + /// Returns a mutable reference to the inner value of the state. + pub fn get_mut(&mut self) -> &mut Q { + 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 + /// [State::map] applies the given function onto the inner value of the state, returning a + /// new state with the result. Essentially, the method describes the mechanism for + /// transfroming the state. + pub fn map(self, f: F) -> State where F: FnOnce(Q) -> R, { - State(f(self.into_inner())) + State(f(self.get())) } /// Replaces the state with a new value, returning the old value. pub fn replace(&mut self, state: Q) -> Q { @@ -72,53 +60,61 @@ impl State { pub fn set(&mut self, state: Q) { self.0 = state; } - /// Replaces the state with a new value, returning the old value. + /// Swaps the inner value of the state with that of the given state. pub fn swap(&mut self, other: &mut S) where - S: RawState, + S: RawState, { core::mem::swap(&mut self.0, other.get_mut()); } + /// Takes the inner value of the state, replacing it with the default value and returning + /// the previous value. + pub fn take(&mut self) -> Q + where + Q: Default, + { + core::mem::take(&mut self.0) + } /// Returns a halted state with an immutable reference to the state. pub fn as_halt(&self) -> State> { State(Halt(self)) } /// Consumes the state and returns a halted state. pub fn into_halt(self) -> State> { - State(Halt(self.into_inner())) + State(Halt(self.get())) } /// Returns a new state with a boxed inner value. pub fn boxed(self) -> State> { - self.map_once(Box::new) + self.map(Box::new) } /// Converts the inner type into a boxed "any" state, returning a new instance of state pub fn as_any(&self) -> State> where Q: Clone + 'static, { - State(Box::new(self.get().clone())) + State(Box::new(self.get_ref().clone())) } /// Converts the inner type into a boxed "any" state, returning a new instance of state pub fn into_any(self) -> State> where Q: 'static, { - State(Box::new(self.into_inner())) + State(Box::new(self.get())) } /// Wraps the inner value of the state with an [`Arc`] and returns a new instance of [State] pub fn shared(self) -> State> { - self.map_once(Arc::new) + self.map(Arc::new) } /// Returns a shared reference to the state. pub fn to_shared(&self) -> State> where Q: Clone, { - State(Arc::new(self.get().clone())) + State(Arc::new(self.get_ref().clone())) } /// Returns a state with an owned inner value. pub fn to_ref(&self) -> State<&Q> { - State(self.get()) + State(self.get_ref()) } /// Returns a state with a mutable reference to the inner value. pub fn to_mut(&mut self) -> State<&mut Q> { @@ -161,7 +157,7 @@ impl State> { where Q: core::any::Any, { - self.into_inner() + self.get() .downcast() .map(State) .map_err(|_| Error::type_error("Failed to downcast state")) @@ -171,7 +167,7 @@ impl State> { where Q: core::any::Any, { - self.get().downcast_ref().map(State) + self.get_ref().downcast_ref().map(State) } } impl State> { @@ -283,7 +279,7 @@ where Q: core::cmp::PartialEq, { fn eq(&self, other: &Q) -> bool { - self.get().eq(other) + self.get_ref().eq(other) } } @@ -292,7 +288,7 @@ where Q: core::cmp::PartialOrd, { fn partial_cmp(&self, other: &Q) -> Option { - self.get().partial_cmp(other) + self.get_ref().partial_cmp(other) } } diff --git a/core/src/types/direction.rs b/core/src/types/direction.rs index be4aa7d..55150c2 100644 --- a/core/src/types/direction.rs +++ b/core/src/types/direction.rs @@ -2,12 +2,6 @@ Appellation: direction Contrib: FL03 */ - -/// [Directional] describes a type containing a direction -pub trait Directional { - fn 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( @@ -152,47 +146,76 @@ impl Default for Direction { impl core::ops::Add for Direction where - T: crate::Decrement + crate::Increment, + T: core::ops::Add + core::ops::Sub + num::One, { type Output = T; fn add(self, rhs: T) -> Self::Output { match self { - Self::Left => rhs.decrement(), - Self::Right => rhs.increment(), + Self::Left => rhs - T::one(), + Self::Right => rhs + T::one(), Self::Stay => rhs, } } } -impl core::ops::Add for isize { - type Output = isize; +macro_rules! impl_apply_direction { + (@impl unsigned: $T:ty) => { + impl core::ops::Add for $T { + type Output = $T; - fn add(self, rhs: Direction) -> Self::Output { - self + rhs as isize - } -} + fn add(self, rhs: Direction) -> Self::Output { + match rhs { + Direction::Left => self.wrapping_sub(1), + Direction::Right => self.wrapping_add(1), + Direction::Stay => self, + } + } + } -impl core::ops::Add for usize { - type Output = usize; + impl core::ops::AddAssign for $T { + fn add_assign(&mut self, rhs: Direction) { + *self = match rhs { + Direction::Left => self.wrapping_sub(1), + Direction::Right => self.wrapping_add(1), + Direction::Stay => 0, + }; + } + } - fn add(self, rhs: Direction) -> Self::Output { - self.wrapping_add_signed(rhs as isize) - } -} + }; + (@impl $T:ty) => { + impl core::ops::Add for $T { + type Output = $T; -impl core::ops::AddAssign for usize { - fn add_assign(&mut self, rhs: Direction) { - *self = core::ops::Add::add(*self, rhs); - } -} + fn add(self, rhs: Direction) -> Self::Output { + self + rhs as $T + } + } -impl core::ops::AddAssign for isize { - fn add_assign(&mut self, rhs: Direction) { - *self = core::ops::Add::add(*self, rhs); - } + impl core::ops::AddAssign for $T { + + fn add_assign(&mut self, rhs: Direction) { + *self += rhs as $T; + } + } + + }; + (unsigned: $($T:ty),* $(,)?) => { + $( + impl_apply_direction!(@impl unsigned: $T); + )* + }; + ($($T:ty),* $(,)?) => { + $( + impl_apply_direction!(@impl $T); + )* + }; } +impl_apply_direction!(i8, i16, i32, i64, i128, isize,); +impl_apply_direction!(unsigned: u8, u16, u32, u64, u128, usize); + mod impl_from { use super::*; use crate::IntoDirection; diff --git a/core/src/types/head.rs b/core/src/types/head.rs index 7c9be8c..afe2e2f 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -63,6 +63,22 @@ impl Head { pub fn with_symbol(self, symbol: S) -> Self { Self { symbol, ..self } } + /// Returns a reference to the current state + pub fn state(&self) -> State<&Q> { + self.state.to_ref() + } + /// Returns a mutable reference to the current [State] + pub fn state_mut(&mut self) -> State<&mut Q> { + self.state.to_mut() + } + /// Returns a reference to the current symbol + pub const fn symbol(&self) -> &S { + &self.symbol + } + /// Returns a mutable reference to the current symbol + pub fn symbol_mut(&mut self) -> &mut S { + &mut self.symbol + } /// Returns a reference to the current state and symbol returing a 2-tuple pub fn as_tuple(&self) -> (&State, &S) { (&self.state, &self.symbol) @@ -83,21 +99,20 @@ impl Head { pub fn set_symbol(&mut self, symbol: S) { self.symbol = symbol; } - /// Returns a reference to the current state - pub fn state(&self) -> State<&Q> { - self.state.to_ref() - } - /// Returns a mutable reference to the current [State] - pub fn state_mut(&mut self) -> State<&mut Q> { - self.state.to_mut() + + pub fn replace(&mut self, state: State, symbol: S) -> Self { + Head { + state: core::mem::replace(&mut self.state, state), + symbol: core::mem::replace(&mut self.symbol, symbol), + } } - /// Returns a reference to the current symbol - pub const fn symbol(&self) -> &S { - &self.symbol + + pub fn replace_state(&mut self, state: State) -> State { + core::mem::replace(&mut self.state, state) } - /// Returns a mutable reference to the current symbol - pub fn symbol_mut(&mut self) -> &mut S { - &mut self.symbol + + pub fn replace_symbol(&mut self, symbol: S) -> S { + core::mem::replace(&mut self.symbol, symbol) } /// Updates the current [State] and symbol pub fn update(&mut self, state: Option>, symbol: Option) { @@ -215,6 +230,73 @@ where } } +impl PartialEq> for Head +where + Q: PartialEq, +{ + fn eq(&self, state: &State) -> bool { + &self.state == state + } +} + +impl PartialEq> for State +where + Q: PartialEq, +{ + fn eq(&self, head: &Head) -> bool { + *self == *head.state + } +} + +impl<'a, Q, S> PartialEq> for State<&'a Q> +where + Q: PartialEq, +{ + fn eq(&self, head: &Head) -> bool { + *self == head.state() + } +} + +impl<'a, Q, S> PartialEq> for Head +where + Q: PartialEq, +{ + fn eq(&self, state: &State<&'a Q>) -> bool { + self.state() == *state + } +} + +impl PartialEq<(State, S)> for Head +where + Q: PartialEq, + S: PartialEq, +{ + fn eq(&self, (state, symbol): &(State, S)) -> bool { + &self.state == state && &self.symbol == symbol + } +} + +impl PartialEq<(Q, S)> for Head +where + State: PartialEq, + Q: PartialEq, + S: PartialEq, +{ + fn eq(&self, (state, symbol): &(Q, S)) -> bool { + &self.state == state && &self.symbol == symbol + } +} + +impl PartialEq> for (State, S) +where + Q: PartialEq, + S: PartialEq, +{ + fn eq(&self, head: &Head) -> bool { + &head.state == &self.0 && &head.symbol == &self.1 + } +} + impl From<(Q, S)> for Head { fn from((state, symbol): (Q, S)) -> Self { Self::new(State(state), symbol) diff --git a/core/tests/rules.rs b/core/tests/rules.rs index d46836d..bed4207 100644 --- a/core/tests/rules.rs +++ b/core/tests/rules.rs @@ -27,7 +27,7 @@ fn ruleset() { let head = Head::new(State(0), 0); // retrieve and validate the tail for the given head assert_eq!( - program.get_head(&head), + program.get_by_head(&head), Some(&Tail::new(Direction::Right, State(1), 1)) ) } diff --git a/core/tests/state.rs b/core/tests/state.rs index 82af521..8cdbc14 100644 --- a/core/tests/state.rs +++ b/core/tests/state.rs @@ -11,26 +11,26 @@ fn state() { // create a new instance of state let state = State::new(0); // validate te functional accessors; get and into_inner - assert_eq!(state.get(), &0); - assert_eq!(state.into_inner(), 0); + assert_eq!(state.get_ref(), &0); + assert_eq!(state.get(), 0); // create a new mutable instance of state let mut state = State::new(0); // replace the inner value with 1 assert_eq!(state.replace(1), 0); // verify the replacement - assert_eq!(*state.get(), 1); + assert_eq!(*state.get_ref(), 1); // set the inner value to 2 state.set(2); // verify the update - assert_eq!(*state.get(), 2); + assert_eq!(*state.get_ref(), 2); // reset the state to its default value state.reset(); // verify the reset - assert_eq!(*state.get(), 0); + assert_eq!(*state.get_ref(), 0); // swap state.swap(&mut State::new(10)); // verify the swap - assert_eq!(*state.get(), 10); + assert_eq!(*state.get_ref(), 10); } #[test] @@ -64,12 +64,12 @@ fn halting() { fn cast_state() { let q = State(0_isize); let r = unsafe { q.cast::() }; - assert_eq!(r.get(), &0_usize); + assert_eq!(r.get_ref(), &0_usize); } #[test] fn convert_state() { let q = State(0_isize); let r = q.into_any(); - assert_eq!(*r.get().downcast_ref::().unwrap(), 0_isize); + assert_eq!(*r.get_ref().downcast_ref::().unwrap(), 0_isize); } diff --git a/rstm/src/models/base.rs b/rstm/src/models/base.rs index 1fae950..2a4d0de 100644 --- a/rstm/src/models/base.rs +++ b/rstm/src/models/base.rs @@ -2,10 +2,9 @@ Appellation: tm Contrib: FL03 */ - -use crate::prelude::{Error, HaltState, Head, StdTape, Symbolic, Tail}; use crate::rules::Program; -use crate::state::State; +use crate::state::{halt::HaltState, State}; +use crate::{Error, Head, StdTape, Symbolic, Tail}; /// # Turing Machine ([StdTm]) /// From 40947037895bdb261b6d7431e6da454c2ffb1f38 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sat, 31 Aug 2024 15:35:10 -0500 Subject: [PATCH 12/27] update Signed-off-by: Joe McCain III --- core/src/actors/engine.rs | 50 +++++-- core/src/lib.rs | 3 - core/src/rules/builders/rule.rs | 6 + core/src/rules/rule.rs | 183 +++++++++++++------------- rstm/src/lib.rs | 3 + {core => rstm}/src/shift/direction.rs | 0 {core => rstm}/src/shift/mod.rs | 0 7 files changed, 136 insertions(+), 109 deletions(-) rename {core => rstm}/src/shift/direction.rs (100%) rename {core => rstm}/src/shift/mod.rs (100%) diff --git a/core/src/actors/engine.rs b/core/src/actors/engine.rs index a7cb565..fa2b942 100644 --- a/core/src/actors/engine.rs +++ b/core/src/actors/engine.rs @@ -2,10 +2,11 @@ Appellation: engine Contrib: FL03 */ +#![cfg(feature = "std")] use crate::state::RawState; -use crate::{Error, Head, Program}; +use crate::{Direction, Error, Head, Program, State}; -use std::collections::HashMap; +use std::collections::hash_map::{self, HashMap}; pub struct Engine where @@ -42,12 +43,33 @@ where pub fn with_program(self, program: Program) -> Self { Self { program, ..self } } + + pub fn position(&self) -> isize { + self.scope.symbol + } + + pub fn cell(&self) -> &Head { + &self.scope + } + + pub fn entry(&mut self) -> hash_map::Entry<'_, isize, A> { + self.tape.entry(self.position()) + } + pub fn read(&self) -> Option<&A> { self.tape.get(&self.scope.symbol) } - pub fn write(&mut self, symbol: A) { - self.tape.insert(self.scope.symbol, symbol); + pub fn write(&mut self, data: A) -> Option { + self.tape.insert(self.position(), data) + } + + fn handle(&mut self, direction: Direction, state: State, symbol: A) { + let next = Head { + state, + symbol: self.position() + direction, + }; + core::mem::replace(&mut self.scope, next); } pub fn process(&mut self) -> Result<(), Error> @@ -55,16 +77,16 @@ where A: crate::Symbolic, Q: Clone + Eq + std::hash::Hash, { - let symbol = self.read().expect("no symbol found"); - if let Some(rule) = self.program.get(self.scope.state(), symbol) { - let next = Head { - state: rule.state.clone(), - symbol: self.scope.symbol + rule.direction, - }; - self.write(rule.symbol); - self.scope = next; - } + let scope = self.cell(); + let symbol = match self.read() { + Some(symbol) => symbol, + None => return Err( Error::runtime_error("Engine::process")), + }; + + if let Some(rule) = self.program.get(self.scope.state(), &symbol) { + self.handle(rule.direction, rule.state.clone(), rule.symbol.clone()); + } - Ok(()) + Ok(()) } } diff --git a/core/src/lib.rs b/core/src/lib.rs index a96c0a8..af2e4de 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -49,8 +49,6 @@ pub(crate) mod seal; pub mod actors; pub mod error; pub mod rules; -#[doc(hidden)] -pub mod shift; pub mod state; pub mod tape; pub mod traits; @@ -60,7 +58,6 @@ pub mod prelude { pub use crate::actors::prelude::*; pub use crate::error::Error; pub use crate::rules::prelude::*; - pub use crate::shift::prelude::*; pub use crate::state::prelude::*; pub use crate::tape::prelude::*; pub use crate::traits::prelude::*; diff --git a/core/src/rules/builders/rule.rs b/core/src/rules/builders/rule.rs index 439fddc..bc70cba 100644 --- a/core/src/rules/builders/rule.rs +++ b/core/src/rules/builders/rule.rs @@ -75,3 +75,9 @@ impl RuleBuilder { } } } + +impl From> for Rule { + fn from(builder: RuleBuilder) -> Self { + builder.build() + } +} \ No newline at end of file diff --git a/core/src/rules/rule.rs b/core/src/rules/rule.rs index da6b877..1870888 100644 --- a/core/src/rules/rule.rs +++ b/core/src/rules/rule.rs @@ -4,45 +4,45 @@ */ use super::RuleBuilder; -use crate::prelude::{Direction, Head, State, Tail}; +use crate::{Head, State, Tail}; #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Rule { - pub head: Head, - pub tail: Tail, +pub struct Rule { + pub head: Head, + pub tail: Tail, } -impl Rule { - pub fn new() -> RuleBuilder { +impl Rule { + pub fn new() -> RuleBuilder { RuleBuilder::new() } /// Returns an immutable reference to the [Head] - pub const fn head(&self) -> &Head { + pub const fn head(&self) -> &Head { &self.head } /// Returns a mutable reference to the [Head] - pub fn head_mut(&mut self) -> &mut Head { + pub fn head_mut(&mut self) -> &mut Head { &mut self.head } /// Returns an instance of the [Head] whose elements are immutable references - pub fn head_ref(&self) -> Head<&'_ Q, &'_ S> { + pub fn head_ref(&self) -> Head<&'_ Q, &'_ A> { self.head().to_ref() } /// Returns an immutable reference to the [Tail] of the [Instruction] - pub const fn tail(&self) -> &Tail { + pub const fn tail(&self) -> &Tail { &self.tail } /// Returns a mutable reference to the [Tail] of the [Instruction] - pub fn tail_mut(&mut self) -> &mut Tail { + pub fn tail_mut(&mut self) -> &mut Tail { &mut self.tail } /// Returns an instance of the [Tail] whose elements are immutable references - pub fn tail_ref(&self) -> Tail<&'_ Q, &'_ S> { + pub fn tail_ref(&self) -> Tail<&'_ Q, &'_ A> { self.tail().to_ref() } /// Returns the direction of the shift - pub fn direction(&self) -> Direction { + pub fn direction(&self) -> crate::Direction { self.tail().direction() } /// Returns the current [State] of the system @@ -50,15 +50,15 @@ impl Rule { self.head().state() } /// Returns the symbol of the [Head] - pub const fn symbol(&self) -> &S { + pub const fn symbol(&self) -> &A { self.head().symbol() } /// Returns the next [Head] of the system - pub fn next_head(&self) -> Head<&'_ Q, &'_ S> { + pub fn next_head(&self) -> Head<&'_ Q, &'_ A> { self.tail().to_head_ref() } /// Consumes the current object and returns the next [Head] of the system - pub fn into_next_head(self) -> Head { + pub fn into_next_head(self) -> Head { self.tail.into_head() } /// Returns the next [State] of the system @@ -66,20 +66,20 @@ impl Rule { self.tail().state() } /// Returns the value which for which the current object will be replaced with - pub const fn write_symbol(&self) -> &S { + pub const fn write_symbol(&self) -> &A { self.tail().symbol() } /// Consumes the current object and returns a 2-tuple consisting of the [Head] and [Tail] - pub fn into_tuple(self) -> (Head, Tail) { + pub fn into_tuple(self) -> (Head, Tail) { (self.head, self.tail) } } -impl<'a, Q, S> Rule<&'a Q, &'a S> { - pub fn cloned(&self) -> Rule +impl<'a, Q, A> Rule<&'a Q, &'a A> { + pub fn cloned(&self) -> Rule where Q: Clone, - S: Clone, + A: Clone, { Rule { head: self.head.cloned(), @@ -87,10 +87,10 @@ impl<'a, Q, S> Rule<&'a Q, &'a S> { } } - pub fn copied(&self) -> Rule + pub fn copied(&self) -> Rule where Q: Copy, - S: Copy, + A: Copy, { Rule { head: self.head.copied(), @@ -99,98 +99,97 @@ impl<'a, Q, S> Rule<&'a Q, &'a S> { } } -impl core::convert::AsRef> for Rule { - fn as_ref(&self) -> &Head { - self.head() - } -} - -impl core::convert::AsRef> for Rule { - fn as_ref(&self) -> &Tail { - self.tail() +mod impls { + use super::Rule; + use crate::{Head, Tail}; + + impl core::convert::AsRef> for Rule { + fn as_ref(&self) -> &Head { + self.head() + } } -} -impl core::convert::AsMut> for Rule { - fn as_mut(&mut self) -> &mut Head { - self.head_mut() + impl core::convert::AsRef> for Rule { + fn as_ref(&self) -> &Tail { + self.tail() + } } -} -impl core::convert::AsMut> for Rule { - fn as_mut(&mut self) -> &mut Tail { - self.tail_mut() + impl core::convert::AsMut> for Rule { + fn as_mut(&mut self) -> &mut Head { + self.head_mut() + } } -} -impl core::borrow::Borrow> for Rule { - fn borrow(&self) -> &Head { - self.head() + impl core::convert::AsMut> for Rule { + fn as_mut(&mut self) -> &mut Tail { + self.tail_mut() + } } -} -impl core::borrow::Borrow> for Rule { - fn borrow(&self) -> &Tail { - self.tail() + impl core::borrow::Borrow> for Rule { + fn borrow(&self) -> &Head { + self.head() + } } -} -impl core::borrow::BorrowMut> for Rule { - fn borrow_mut(&mut self) -> &mut Head { - self.head_mut() + impl core::borrow::Borrow> for Rule { + fn borrow(&self) -> &Tail { + self.tail() + } } -} -impl core::borrow::BorrowMut> for Rule { - fn borrow_mut(&mut self) -> &mut Tail { - self.tail_mut() + impl core::borrow::BorrowMut> for Rule { + fn borrow_mut(&mut self) -> &mut Head { + self.head_mut() + } } -} -impl PartialEq<(Head, Tail)> for Rule -where - Q: PartialEq, - S: PartialEq, -{ - fn eq(&self, other: &(Head, Tail)) -> bool { - &self.head == &other.0 && &self.tail == &other.1 + impl core::borrow::BorrowMut> for Rule { + fn borrow_mut(&mut self) -> &mut Tail { + self.tail_mut() + } } -} -impl PartialEq> for Rule -where - Q: PartialEq, - S: PartialEq, -{ - fn eq(&self, other: &Head) -> bool { - &self.head == other + impl PartialEq<(Head, Tail)> for Rule + where + Q: PartialEq, + S: PartialEq, + { + fn eq(&self, other: &(Head, Tail)) -> bool { + &self.head == &other.0 && &self.tail == &other.1 + } } -} -impl PartialEq> for Rule -where - Q: PartialEq, - S: PartialEq, -{ - fn eq(&self, other: &Tail) -> bool { - &self.tail == other + impl PartialEq> for Rule + where + Q: PartialEq, + S: PartialEq, + { + fn eq(&self, other: &Head) -> bool { + &self.head == other + } } -} -impl From<(Head, Tail)> for Rule { - fn from((head, tail): (Head, Tail)) -> Self { - Self { head, tail } + impl PartialEq> for Rule + where + Q: PartialEq, + S: PartialEq, + { + fn eq(&self, other: &Tail) -> bool { + &self.tail == other + } } -} -impl From> for (Head, Tail) { - fn from(rule: Rule) -> Self { - (rule.head, rule.tail) + impl From<(Head, Tail)> for Rule { + fn from((head, tail): (Head, Tail)) -> Self { + Self { head, tail } + } } -} -impl From> for Rule { - fn from(builder: RuleBuilder) -> Self { - builder.build() + impl From> for (Head, Tail) { + fn from(rule: Rule) -> Self { + (rule.head, rule.tail) + } } } diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index 7aaea4a..abd0c3f 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -17,7 +17,10 @@ pub use self::models::StdTM; #[doc(inline)] pub use rstm_core::*; +#[doc(hidden)] pub mod models; +#[doc(hidden)] +pub mod shift; pub mod prelude { pub use super::models::prelude::*; diff --git a/core/src/shift/direction.rs b/rstm/src/shift/direction.rs similarity index 100% rename from core/src/shift/direction.rs rename to rstm/src/shift/direction.rs diff --git a/core/src/shift/mod.rs b/rstm/src/shift/mod.rs similarity index 100% rename from core/src/shift/mod.rs rename to rstm/src/shift/mod.rs From 05b2f7f7fa77fb425ac06f231e9ba91a9b83aa0f Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sun, 1 Sep 2024 14:12:22 -0500 Subject: [PATCH 13/27] updated the `state` module Signed-off-by: Joe McCain III --- core/src/actors/engine.rs | 6 +- core/src/rules/builders/rule.rs | 2 +- core/src/rules/rule.rs | 2 +- core/src/state/halt/mod.rs | 10 ++ core/src/state/halt/state.rs | 25 ++- core/src/state/halt/wrap.rs | 2 +- core/src/state/impls/impl_ext.rs | 103 ++++++++++++ core/src/state/impls/impl_ops.rs | 233 ++++++++++++++++++++++++++ core/src/state/impls/impl_repr.rs | 123 ++++++++++++++ core/src/state/mod.rs | 6 + core/src/state/state.rs | 260 +++--------------------------- core/tests/state.rs | 43 +++-- rstm/src/shift/mod.rs | 1 + 13 files changed, 550 insertions(+), 266 deletions(-) create mode 100644 core/src/state/impls/impl_ext.rs create mode 100644 core/src/state/impls/impl_ops.rs create mode 100644 core/src/state/impls/impl_repr.rs diff --git a/core/src/actors/engine.rs b/core/src/actors/engine.rs index fa2b942..44eac2d 100644 --- a/core/src/actors/engine.rs +++ b/core/src/actors/engine.rs @@ -80,13 +80,13 @@ where let scope = self.cell(); let symbol = match self.read() { Some(symbol) => symbol, - None => return Err( Error::runtime_error("Engine::process")), + None => return Err(Error::runtime_error("Engine::process")), }; if let Some(rule) = self.program.get(self.scope.state(), &symbol) { self.handle(rule.direction, rule.state.clone(), rule.symbol.clone()); - } + } - Ok(()) + Ok(()) } } diff --git a/core/src/rules/builders/rule.rs b/core/src/rules/builders/rule.rs index bc70cba..91f58c7 100644 --- a/core/src/rules/builders/rule.rs +++ b/core/src/rules/builders/rule.rs @@ -80,4 +80,4 @@ impl From> for Rule { fn from(builder: RuleBuilder) -> Self { builder.build() } -} \ No newline at end of file +} diff --git a/core/src/rules/rule.rs b/core/src/rules/rule.rs index 1870888..eed4776 100644 --- a/core/src/rules/rule.rs +++ b/core/src/rules/rule.rs @@ -102,7 +102,7 @@ impl<'a, Q, A> Rule<&'a Q, &'a A> { mod impls { use super::Rule; use crate::{Head, Tail}; - + impl core::convert::AsRef> for Rule { fn as_ref(&self) -> &Head { self.head() diff --git a/core/src/state/halt/mod.rs b/core/src/state/halt/mod.rs index 52554a6..fc30cd1 100644 --- a/core/src/state/halt/mod.rs +++ b/core/src/state/halt/mod.rs @@ -83,6 +83,16 @@ impl Haltable for Option> { } } +impl HaltableExt for Halt { + fn get(self) -> Option { + Some(self.0) + } + + fn get_mut(&mut self) -> Option<&mut Q> { + Some(&mut self.0) + } +} + impl HaltableExt for Option> { fn get(self) -> Option { self.map(|state| state.get()) diff --git a/core/src/state/halt/state.rs b/core/src/state/halt/state.rs index d03825d..359662f 100644 --- a/core/src/state/halt/state.rs +++ b/core/src/state/halt/state.rs @@ -13,14 +13,15 @@ impl Halt { Self(halt) } #[inline] - pub fn into_inner(self) -> Q { + /// Consumes the halted state and returns the inner value. + pub fn get(self) -> Q { self.0 } - - pub const fn get(&self) -> &Q { + /// Returns an immutable reference to the inner value of the halted state. + pub const fn get_ref(&self) -> &Q { &self.0 } - + /// Returns a mutable reference to the inner value of the halted state. pub fn get_mut(&mut self) -> &mut Q { &mut self.0 } @@ -29,7 +30,7 @@ impl Halt { pub fn replace(&mut self, halt: Q) -> Q { core::mem::replace(&mut self.0, halt) } - + /// Resets the inner value of the halted state to the default value of the type. pub fn reset(&mut self) where Q: Default, @@ -47,11 +48,21 @@ impl Halt { { core::mem::swap(&mut self.0, other.get_mut()); } - /// Converts the halted state into a new [State] with an immutable reference to the inner value. + /// Takes the inner value of the halted state and replaces it with the default value of + /// the type. + pub fn take(&mut self) -> Q + where + Q: Default, + { + core::mem::take(&mut self.0) + } + /// Converts the halted state into a new [State] with an immutable reference to the inner + /// value. pub fn as_state(&self) -> State> { State(Halt(&self.0)) } - /// Converts the halted state into a new [State] with a mutable reference to the inner value. + /// Converts the halted state into a new [State] with a mutable reference to the inner + /// value. pub fn as_state_mut(&mut self) -> State> { State(Halt(&mut self.0)) } diff --git a/core/src/state/halt/wrap.rs b/core/src/state/halt/wrap.rs index e4fefb2..469fa95 100644 --- a/core/src/state/halt/wrap.rs +++ b/core/src/state/halt/wrap.rs @@ -57,7 +57,7 @@ impl HaltState { pub fn get(&self) -> &Q { match self { Self::State(inner) => inner.get_ref(), - Self::Halt(inner) => inner.get(), + Self::Halt(inner) => inner.get_ref(), } } diff --git a/core/src/state/impls/impl_ext.rs b/core/src/state/impls/impl_ext.rs new file mode 100644 index 0000000..c54e2b1 --- /dev/null +++ b/core/src/state/impls/impl_ext.rs @@ -0,0 +1,103 @@ +/* + Appellation: impl_ext + Contrib: FL03 +*/ +use crate::state::State; + +/* + ************* References ************* +*/ +impl core::convert::AsRef for State { + fn as_ref(&self) -> &Q { + &self.0 + } +} + +impl core::convert::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 + } +} + +/* + ************* Comparisons ************* +*/ +impl core::cmp::PartialEq for State +where + Q: core::cmp::PartialEq, +{ + fn eq(&self, other: &Q) -> bool { + self.get_ref().eq(other) + } +} + +impl core::cmp::PartialOrd for State +where + Q: core::cmp::PartialOrd, +{ + fn partial_cmp(&self, other: &Q) -> Option { + self.get_ref().partial_cmp(other) + } +} + +/* + ************* Conversions ************* +*/ +impl From for State { + fn from(state: Q) -> Self { + State(state) + } +} + +/* + ************* Markers ************* +*/ +unsafe impl core::marker::Send for State where Q: core::marker::Send {} + +unsafe impl core::marker::Sync for State where Q: core::marker::Sync {} + +/* + ************* Formatting ************* +*/ +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); diff --git a/core/src/state/impls/impl_ops.rs b/core/src/state/impls/impl_ops.rs new file mode 100644 index 0000000..1bbfd8b --- /dev/null +++ b/core/src/state/impls/impl_ops.rs @@ -0,0 +1,233 @@ +/* + Appellation: impl_ops + Contrib: FL03 +*/ +use crate::state::State; + +impl core::ops::Neg for State +where + Q: core::ops::Neg, +{ + type Output = State; + + fn neg(self) -> Self::Output { + State(core::ops::Neg::neg(self.0)) + } +} + +impl<'a, Q> core::ops::Neg for &'a State +where + &'a Q: core::ops::Neg, +{ + type Output = State<<&'a Q as core::ops::Neg>::Output>; + + fn neg(self) -> Self::Output { + State(core::ops::Neg::neg(self.get_ref())) + } +} + +impl core::ops::Not for State +where + Q: core::ops::Not, +{ + type Output = State; + + fn not(self) -> Self::Output { + State(core::ops::Not::not(self.0)) + } +} + +impl<'a, Q> core::ops::Not for &'a State +where + &'a Q: core::ops::Not, +{ + type Output = State<<&'a Q as core::ops::Not>::Output>; + + fn not(self) -> Self::Output { + State(core::ops::Not::not(self.get_ref())) + } +} + +impl num::traits::Num for State where Q: num::traits::Num { + type FromStrRadixErr = Q::FromStrRadixErr; + + fn from_str_radix(str: &str, radix: u32) -> Result { + Q::from_str_radix(str, radix).map(State) + } +} + +impl num::traits::One for State +where + Q: PartialEq + num::traits::One, +{ + fn one() -> Self { + State(Q::one()) + } + + fn is_one(&self) -> bool { + self.0.is_one() + } +} + +impl num::traits::Zero for State +where + Q: num::traits::Zero, +{ + fn zero() -> Self { + State(Q::zero()) + } + + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +macro_rules! impl_assign_ops { + (@impl $trait:ident::$call:ident) => { + impl ::core::ops::$trait for $crate::state::State { + fn $call(&mut self, rhs: $crate::state::State) { + ::core::ops::$trait::$call(self.get_mut(), rhs.get()) + } + } + + impl ::core::ops::$trait for $crate::state::State { + fn $call(&mut self, rhs: Q) { + ::core::ops::$trait::$call(self.get_mut(), rhs) + } + } + }; + (alt: $($trait:ident::$call:ident),* $(,)?) => { + paste::paste! { + impl_assign_ops!($([<$trait Assign>]::[<$call _assign>]),*); + } + }; + ($($trait:ident::$call:ident),* $(,)?) => { + $( + impl_assign_ops!(@impl $trait::$call); + )* + }; +} + +macro_rules! impl_ops { + (@impl $trait:ident::$call:ident) => { + impl ::core::ops::$trait for State + where + Q: ::core::ops::$trait, + { + type Output = State; + + fn $call(self, rhs: State) -> Self::Output { + State(::core::ops::$trait::$call(self.get(), rhs.get())) + } + } + + impl<'a, Q> ::core::ops::$trait<&'a State> for State + where + Q: ::core::ops::$trait<&'a Q>, + { + type Output = State; + + fn $call(self, rhs: &'a State) -> Self::Output { + State(::core::ops::$trait::$call(self.get(), rhs.get_ref())) + } + } + + impl<'a, Q> ::core::ops::$trait> for &'a State + where + &'a Q: ::core::ops::$trait, + { + type Output = State<<&'a Q as ::core::ops::$trait>::Output>; + + fn $call(self, rhs: State) -> Self::Output { + State(::core::ops::$trait::$call(self.get_ref(), rhs.get())) + } + } + + impl<'a, Q> ::core::ops::$trait<&'a State> for &'a State + where + &'a Q: ::core::ops::$trait<&'a Q>, + { + type Output = State<<&'a Q as ::core::ops::$trait<&'a Q>>::Output>; + + fn $call(self, rhs: &'a State) -> Self::Output { + State(::core::ops::$trait::$call(self.get_ref(), rhs.get_ref())) + } + } + }; + (@inner $trait:ident::$call:ident) => { + impl ::core::ops::$trait for State + where + Q: ::core::ops::$trait, + { + type Output = State; + + fn $call(self, rhs: Q) -> Self::Output { + State(::core::ops::$trait::$call(self.get(), rhs)) + } + } + + impl<'a, Q> ::core::ops::$trait<&'a Q> for State + where + Q: ::core::ops::$trait<&'a Q>, + { + type Output = State; + + fn $call(self, rhs: &'a Q) -> Self::Output { + State(::core::ops::$trait::$call(self.get(), rhs)) + } + } + + impl<'a, Q> ::core::ops::$trait for State<&'a Q> + where + &'a Q: ::core::ops::$trait, + { + type Output = State<<&'a Q as ::core::ops::$trait>::Output>; + + fn $call(self, rhs: Q) -> Self::Output { + State(::core::ops::$trait::$call(self.get(), rhs)) + } + } + + impl<'a, Q> ::core::ops::$trait for &'a State + where + &'a Q: ::core::ops::$trait, + { + type Output = State<<&'a Q as ::core::ops::$trait>::Output>; + + fn $call(self, rhs: Q) -> Self::Output { + State(::core::ops::$trait::$call(self.get_ref(), rhs)) + } + } + + impl<'a, Q> ::core::ops::$trait<&'a Q> for &'a State + where + &'a Q: ::core::ops::$trait<&'a Q>, + { + type Output = State<<&'a Q as ::core::ops::$trait<&'a Q>>::Output>; + + fn $call(self, rhs: &'a Q) -> Self::Output { + State(::core::ops::$trait::$call(self.get_ref(), rhs)) + } + } + }; + ($($trait:ident::$call:ident),* $(,)?) => { + $( + impl_ops!(@impl $trait::$call); + impl_ops!(@inner $trait::$call); + impl_assign_ops!(alt: $trait::$call); + )* + }; +} + +impl_ops! { + Add::add, + BitAnd::bitand, + BitOr::bitor, + BitXor::bitxor, + Div::div, + Mul::mul, + Rem::rem, + Shl::shl, + Shr::shr, + Sub::sub, +} diff --git a/core/src/state/impls/impl_repr.rs b/core/src/state/impls/impl_repr.rs new file mode 100644 index 0000000..90d0462 --- /dev/null +++ b/core/src/state/impls/impl_repr.rs @@ -0,0 +1,123 @@ +/* + Appellation: impl_repr + Contrib: FL03 +*/ +use crate::error::Error; +use crate::state::{Halt, State}; +use core::mem::MaybeUninit; + +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 State<*const Q> { + /// Creates a new instance of state with a raw pointer to the inner value. + pub fn from_ptr(ptr: *const Q) -> Self { + Self(ptr) + } +} + +impl State> { + /// Creates a new instance of state with an initialized inner value. + pub fn init(value: Q) -> Self { + Self(MaybeUninit::new(value)) + } + /// Creates a new instance of state with an uninitialized inner value. + pub const fn uninit() -> Self { + Self(MaybeUninit::uninit()) + } + /// Converts the state into a new instance of [State] with an initialized state. + pub fn assume_init(self) -> State { + State(unsafe { self.get().assume_init() }) + } +} + +impl State<()> { + /// Creates a new instance of [State] with an empty state. + pub fn empty() -> Self { + Self(()) + } +} + +impl State> { + /// Attempts to downcast the state to a concrete type `Q`; returns an error if the state + /// is not of type `Q`. + pub fn downcast(self) -> Result>, Error> + where + Q: core::any::Any, + { + self.get() + .downcast() + .map(State) + .map_err(|_| Error::type_error("Failed to downcast state")) + } + /// Returns an immutable reference to the state if it is of type `Q`; returns `None` + /// otherwise. + pub fn downcast_ref(&self) -> Option> + where + Q: core::any::Any, + { + self.get_ref().downcast_ref().map(State) + } + + /// Returns a mutable reference to the state if it is of type `Q`; returns `None` + /// otherwise. + pub fn downcast_mut(&mut self) -> Option> + where + Q: core::any::Any, + { + self.get_mut().downcast_mut().map(State) + } +} + +impl State> { + /// Creates a new instance of state whose inner state is [Option::None]. + pub fn none() -> Self { + Self(None) + } + /// Creates a new instance of state whose inner state is [Option::Some]. + pub fn some(value: Q) -> Self { + Self(Some(value)) + } +} + +impl State> { + /// Creates a new instance of [State] from a [Halt] state. + pub fn halted(Halt(inner): Halt) -> Self { + Self(Halt(inner)) + } + /// Converts the halted state into an unhalted state. + pub fn unhalt(self) -> State { + State(self.get().get()) + } +} diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index 90b6ee8..b35c6e7 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -9,6 +9,12 @@ pub(crate) mod state; pub mod halt; +mod impls { + pub mod impl_ext; + pub mod impl_ops; + pub mod impl_repr; +} + pub(crate) mod states { #[doc(inline)] pub use self::binary::*; diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 80287ee..0d64ca8 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -3,18 +3,26 @@ Contrib: FL03 */ use super::{Halt, RawState}; -use crate::Error; -use std::sync::Arc; -/// + +/// [State] is a generalized state implementation, representing the state of a system or +/// object. #[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); +pub struct State(pub Q); impl State { - pub fn new(state: Q) -> Self { + pub fn from_value(state: Q) -> Self { Self(state) } + /// Returns a new instance of state with a raw pointer to the inner value. + pub fn as_ptr(&self) -> *const Q { + core::ptr::addr_of!(self.0) + } + /// Returns a new instance of state with a mutable raw pointer to the inner value. + pub fn as_mut_ptr(&mut self) -> *mut Q { + core::ptr::addr_of_mut!(self.0) + } /// Casts the state to a new type, returning a new instance of [State]. /// /// ### Saftey @@ -101,16 +109,18 @@ impl State { { State(Box::new(self.get())) } + #[cfg(feature = "std")] /// Wraps the inner value of the state with an [`Arc`] and returns a new instance of [State] - pub fn shared(self) -> State> { - self.map(Arc::new) + pub fn shared(self) -> State> { + self.map(std::sync::Arc::new) } + #[cfg(feature = "std")] /// Returns a shared reference to the state. - pub fn to_shared(&self) -> State> + pub fn to_shared(&self) -> State> where Q: Clone, { - State(Arc::new(self.get_ref().clone())) + self.clone().shared() } /// Returns a state with an owned inner value. pub fn to_ref(&self) -> State<&Q> { @@ -143,235 +153,3 @@ impl State { core::any::TypeId::of::() == core::any::TypeId::of::>>() } } - -impl State<()> { - /// Creates a new instance of [State] with an empty state. - pub fn empty() -> Self { - Self(()) - } -} - -impl State> { - /// Downcasts the state to a new type, returning a new instance of [State]. - pub fn downcast(self) -> Result>, Error> - where - Q: core::any::Any, - { - self.get() - .downcast() - .map(State) - .map_err(|_| Error::type_error("Failed to downcast state")) - } - - pub fn downcast_ref(&self) -> Option> - where - Q: core::any::Any, - { - self.get_ref().downcast_ref().map(State) - } -} -impl State> { - /// Creates a new instance of [State] from a [Halt] state. - pub fn halted(Halt(inner): Halt) -> Self { - Self(Halt(inner)) - } - - pub fn unhalt(self) -> State { - State(self.0.into_inner()) - } -} - -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 core::convert::AsRef for State { - fn as_ref(&self) -> &Q { - &self.0 - } -} - -impl core::convert::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.get_ref().eq(other) - } -} - -impl core::cmp::PartialOrd for State -where - Q: core::cmp::PartialOrd, -{ - fn partial_cmp(&self, other: &Q) -> Option { - self.get_ref().partial_cmp(other) - } -} - -impl From for State { - fn from(state: Q) -> Self { - State(state) - } -} - -macro_rules! impl_ops { - (@alt $trait:ident::$call:ident) => { - impl ::core::ops::$trait for State - where - Q: ::core::ops::$trait, - R: $crate::state::RawState, - { - type Output = State; - - fn $call(self, rhs: State) -> Self::Output { - State(::core::ops::$trait::$call(self.into_inner(), rhs.into_inner())) - } - } - }; - (@impl $trait:ident::$call:ident) => { - impl ::core::ops::$trait for State - where - Q: ::core::ops::$trait, - { - type Output = State; - - fn $call(self, rhs: State) -> Self::Output { - State(::core::ops::$trait::$call(self.into_inner(), rhs.into_inner())) - } - } - - impl ::core::ops::$trait for State - where - Q: core::ops::$trait, - { - type Output = State; - - fn $call(self, rhs: Q) -> Self::Output { - State(::core::ops::$trait::$call(self.into_inner(), rhs)) - } - } - - paste::paste! { - impl ::core::ops::[<$trait Assign>]> for State - where - Q: ::core::ops::[<$trait Assign>], - { - - fn [<$call _assign>](&mut self, rhs: State) { - ::core::ops::[<$trait Assign>]::[<$call _assign>](self.get_mut(), rhs.into_inner()) - } - } - impl ::core::ops::[<$trait Assign>] for State - where - Q: ::core::ops::[<$trait Assign>], - { - - fn [<$call _assign>](&mut self, rhs: Q) { - ::core::ops::[<$trait Assign>]::[<$call _assign>](self.get_mut(), rhs) - } - } - } - }; - ($($trait:ident::$call:ident),* $(,)?) => { - $( - impl_ops!(@impl $trait::$call); - )* - }; -} - -impl_ops! { - Add::add, - BitAnd::bitand, - BitOr::bitor, - BitXor::bitxor, - Div::div, - Mul::mul, - Rem::rem, - Shl::shl, - Shr::shr, - Sub::sub, -} diff --git a/core/tests/state.rs b/core/tests/state.rs index 8cdbc14..27b68db 100644 --- a/core/tests/state.rs +++ b/core/tests/state.rs @@ -9,12 +9,12 @@ use rstm::state::{Halt, State}; #[test] fn state() { // create a new instance of state - let state = State::new(0); - // validate te functional accessors; get and into_inner + let state = State::from_value(0); + // validate the functional accessors; get and into_inner assert_eq!(state.get_ref(), &0); assert_eq!(state.get(), 0); // create a new mutable instance of state - let mut state = State::new(0); + let mut state = State::from_value(0); // replace the inner value with 1 assert_eq!(state.replace(1), 0); // verify the replacement @@ -28,7 +28,7 @@ fn state() { // verify the reset assert_eq!(*state.get_ref(), 0); // swap - state.swap(&mut State::new(10)); + state.swap(&mut State::from_value(10)); // verify the swap assert_eq!(*state.get_ref(), 10); } @@ -37,39 +37,58 @@ fn state() { fn halting() { // create a new instance of state let state = Halt::new(0); - // validate te functional accessors; get and into_inner - assert_eq!(state.get(), &0); - assert_eq!(state.into_inner(), 0); + // validate the functional accessors; get and into_inner + assert_eq!(state.get_ref(), &0); + assert_eq!(state.get(), 0); // create a new mutable instance of state let mut state = Halt::new(0); // replace the inner value with 1 assert_eq!(state.replace(1), 0); // verify the replacement - assert_eq!(*state.get(), 1); + assert_eq!(*state.get_ref(), 1); // set the inner value to 2 state.set(2); // verify the update - assert_eq!(*state.get(), 2); + assert_eq!(*state.get_ref(), 2); // reset the state to its default value state.reset(); // verify the reset - assert_eq!(*state.get(), 0); + assert_eq!(*state.get_ref(), 0); // swap state.swap(&mut Halt::new(10)); // verify the swap - assert_eq!(*state.get(), 10); + assert_eq!(*state.get_ref(), 10); } #[test] fn cast_state() { + // create a new instance of state with a value of 0_isize let q = State(0_isize); + // cast the state to a usize let r = unsafe { q.cast::() }; - assert_eq!(r.get_ref(), &0_usize); + // verify the casted state has an inner value of 0 + assert_eq!(r, 0_usize); } #[test] fn convert_state() { + // create a new instance of state with a value of 0 let q = State(0_isize); + // convert the state into an Any let r = q.into_any(); + // verify the converted state has an inner value of 0 assert_eq!(*r.get_ref().downcast_ref::().unwrap(), 0_isize); } + +#[test] +fn numstate() { + use num::{One, Zero}; + // create a new instance of state with a value of 1 + let one = State::::one(); + // create a new instance of state with a value of 0_f64 + let zero = State::::zero(); + // verify the state has an inner value of 1 + assert_eq!(one, 1); + // verify the state has an inner value of 0 + assert_eq!(zero, 0.0); +} \ No newline at end of file diff --git a/rstm/src/shift/mod.rs b/rstm/src/shift/mod.rs index 6844a87..236eddf 100644 --- a/rstm/src/shift/mod.rs +++ b/rstm/src/shift/mod.rs @@ -7,6 +7,7 @@ pub use self::direction::{LinearShift, ShiftDirection}; pub(crate) mod direction; +#[allow(unused_imports)] pub(crate) mod prelude { pub use super::direction::*; } From c37880d0ccefc01a4619a27c2ba7477fd10c2d94 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sun, 1 Sep 2024 14:13:16 -0500 Subject: [PATCH 14/27] update Signed-off-by: Joe McCain III --- .github/workflows/rust.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 74ebb0d..306d0cc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -10,7 +10,8 @@ env: on: pull_request: - branches: [ main ] + branches: [ main, v*.*.* ] + branches-ignore: [ *-beta, *-dev, *-nightly ] release: types: [ created ] repository_dispatch: From 95470b006b9b2ec04c84581c41d2d689bf4b9211 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sun, 1 Sep 2024 14:28:51 -0500 Subject: [PATCH 15/27] update Signed-off-by: Joe McCain III --- .github/FUNDING.yml | 2 +- .github/dependabot.yml | 6 ++-- README.md | 66 +++++++++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index c26b651..d2a0934 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -github: [FL03] +github: [ FL03 ] diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d1b4660..cf186bb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,16 +3,16 @@ updates: - package-ecosystem: cargo directory: / schedule: - interval: weekly + interval: monthly - package-ecosystem: github-actions directory: / schedule: - interval: weekly + interval: monthly - package-ecosystem: cargo directory: /rstm schedule: interval: weekly - package-ecosystem: cargo - directory: /rstm-core + directory: /core schedule: interval: weekly diff --git a/README.md b/README.md index 270d810..273adcb 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,12 @@ # rstm - +[![license](https://img.shields.io/crates/l/rstm.svg)](https://crates.io/crates/rstm) [![crates.io](https://img.shields.io/crates/v/rstm.svg)](https://crates.io/crates/rstm) [![docs.rs](https://docs.rs/rstm/badge.svg)](https://docs.rs/rstm) + [![clippy](https://github.com/FL03/rstm/actions/workflows/clippy.yml/badge.svg)](https://github.com/FL03/rstm/actions/workflows/clippy.yml) [![rust](https://github.com/FL03/rstm/actions/workflows/rust.yml/badge.svg)](https://github.com/FL03/rstm/actions/workflows/rust.yml) -[![license](https://img.shields.io/crates/l/rstm.svg)](https://crates.io/crates/rstm) -[![lines of code](https://tokei.rs/b1/github/FL03/rstm?category=code)](https://tokei.rs/b1/github/FL03/rstm?category=code) - *** _**The library is currently in the early stages of development and is still settling in on a feel for the api.**_ @@ -33,18 +31,13 @@ cargo build --all-features --workspace #### _Run an example_ ```bash -cargo run -f F --example actor +cargo run -f F --example {actor} ``` ## Usage ### Creating a new ruleset -Programs are essentially collections of rules that define the behavior of the machine. Facilitating the creation of these rules is the `ruleset!` macro. The macro allows developers to define a set of rules for the machine in a concise and readable manner while further emulating the transition function defined by "On topological dynamics of Turing machines" by Petr Kůrka; `δ: Q x A -> Q x A x {-1, 0, 1}.` - - -`ruleset!` is a macro that allows you to define a set of rules for the machine. The syntax is as follows: - ```rust ruleset![ (state, symbol) -> Direction(next_state, next_symbol), @@ -52,11 +45,37 @@ Programs are essentially collections of rules that define the behavior of the ma ] ``` -The macro is hygenic, meaning developers will not need to import the `Direction` enum nor its variants in order to use the macro. +Programs are essentially collections of rules that define the behavior of the machine. Facilitating the creation of these rules is the `ruleset!` macro. The macro allows developers to define a set of rules for the machine in a concise and readable manner while further emulating the transition function $\delta$ defined by "On topological dynamics of Turing machines" by Petr Kůrka: + +$$ +\delta: Q \times A \rarr Q\times{A}\times{\bigl\{0, \pm{1}\bigr\}}. +$$ + +The macro expands into a `Vec` where `Rule` is structure consisting of two other structures, namely: `Head` and the `Tail`. Each of these structures is a direct representation of the two sides of the transition function defined above + +```rust + pub struct Rule { + pub head: Head, + pub tail: Tail, + } + + pub struct Head { + pub state: Q, + pub symbol: S, + } + + pub struct Tail { + pub direction: Direction, + pub state: Q, + pub symbol: S, + } +``` +**Note:** the macro is hygenic, meaning developers will not need to import the `Direction` enum nor its variants in order to use the macro. +#### _Example_ -#### Example: Building a ruleset for a three-state, two-symbol Turing machine +The following example demonstrates the use of the `ruleset!` macro to define a set of rules for a three-state, two-symbol Turing machine. ```rust use rstm::ruleset; @@ -74,6 +93,8 @@ The macro is hygenic, meaning developers will not need to import the `Direction` ### Examples +#### _Executing a program using an `Actor`_ + ```rust extern crate rstm; @@ -81,11 +102,10 @@ The macro is hygenic, meaning developers will not need to import the `Direction` fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); - // initialize the tape data - let alpha = vec![0i8; 10]; + let alpha = vec![0u8; 10]; // initialize the state of the machine - let initial_state = State(0); + let initial_state = State::::default(); // define the ruleset for the machine let rules = ruleset![ (0, 0) -> Right(1, 0), @@ -95,14 +115,11 @@ The macro is hygenic, meaning developers will not need to import the `Direction` (-1, 0) -> Left(0, 0), (-1, 1) -> Left(1, 1), ]; - - let program = Program::new() - .initial_state(initial_state) - .rules(rules) - .build(); - + // create a new program from the ruleset + let program = Program::from_iter(rules); // create a new instance of the machine - let tm = dbg!(Actor::from_state(initial_state).with_tape(alpha)); + let tm = dbg!(Actor::new(alpha, initial_state, 0)); + // execute the program tm.execute(program).run()?; Ok(()) } @@ -111,8 +128,3 @@ The macro is hygenic, meaning developers will not need to import the `Direction` ## Contributing Pull requests are welcome. Any improvements or modifactions should first be disccussed using a pull-request and/or by opening an issue. Additionally, please make sure to update tests as appropriate and to adhear to the feature gates. - -## License - -* [Apache-2.0](https://choosealicense.com/licenses/apache-2.0/) -* [MIT](https://choosealicense.com/licenses/mit/) From 422c89b81d21d9adb1bb7fb0eee64f2d77ca7e80 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sun, 1 Sep 2024 14:53:08 -0500 Subject: [PATCH 16/27] update Signed-off-by: Joe McCain III --- core/src/state/impls/impl_repr.rs | 11 +++++++++++ core/src/traits/symbols.rs | 1 + 2 files changed, 12 insertions(+) diff --git a/core/src/state/impls/impl_repr.rs b/core/src/state/impls/impl_repr.rs index 90d0462..ec9270e 100644 --- a/core/src/state/impls/impl_repr.rs +++ b/core/src/state/impls/impl_repr.rs @@ -47,6 +47,13 @@ impl State<*const Q> { } } +impl State<*mut Q> { + /// Creates a new instance of state with a mutable raw pointer to the inner value. + pub fn from_mut_ptr(ptr: *mut Q) -> Self { + Self(ptr) + } +} + impl State> { /// Creates a new instance of state with an initialized inner value. pub fn init(value: Q) -> Self { @@ -60,6 +67,10 @@ impl State> { pub fn assume_init(self) -> State { State(unsafe { self.get().assume_init() }) } + /// Writes a value to the inner state. + pub fn write(&mut self, value: Q) -> &mut Q { + self.get_mut().write(value) + } } impl State<()> { diff --git a/core/src/traits/symbols.rs b/core/src/traits/symbols.rs index 57766d2..33c3d28 100644 --- a/core/src/traits/symbols.rs +++ b/core/src/traits/symbols.rs @@ -79,6 +79,7 @@ impl Alphabet for [S] { } } +#[cfg(feature = "alloc")] impl Alphabet for Vec { type Elem = S; From d9dc7febb040de8dbf6c775d28b5edd967613bae Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sun, 1 Sep 2024 15:02:42 -0500 Subject: [PATCH 17/27] update Signed-off-by: Joe McCain III --- core/src/state/mod.rs | 42 ++++----- core/src/state/states/binary.rs | 154 -------------------------------- 2 files changed, 15 insertions(+), 181 deletions(-) delete mode 100644 core/src/state/states/binary.rs diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index b35c6e7..910c202 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{halt::*, state::State, states::*}; +pub use self::{halt::*, state::State}; pub(crate) mod state; @@ -14,22 +14,18 @@ mod impls { pub mod impl_ops; pub mod impl_repr; } - -pub(crate) mod states { - #[doc(inline)] - pub use self::binary::*; - - pub(crate) mod binary; -} - pub(crate) mod prelude { pub use super::halt::Haltable; pub use super::state::State; - pub use super::states::*; + #[cfg(feature = "std")] pub use super::AnyState; + pub use super::MaybeState; } +#[cfg(feature = "std")] /// A type alias for a [State] whose inner value is the dynamically sized type of a boxed [`Any`](core::any::Any). -pub type AnyState = State>; +pub type AnyState = State>; +/// A type alias for a [State] whose inner value is a [core::mem::MaybeUninit] of generic type `Q`. +pub type MaybeState = State>; /// [RawState] is a trait describing objects capable of being used as states in our library. /// The trait contains a single associated trait, the context, or inner value of the state. @@ -39,9 +35,9 @@ pub trait RawState { private!(); - fn into_inner(self) -> Self::Q; + fn get(self) -> Self::Q; - fn get(&self) -> &Self::Q; + fn get_ref(&self) -> &Self::Q; fn get_mut(&mut self) -> &mut Self::Q; @@ -49,19 +45,10 @@ pub trait RawState { } #[doc(hidden)] -pub trait Stateful { - type State: RawState; +pub trait Apply { + type Output; - fn get(self) -> Q; - - fn get_mut(&mut self) -> &mut Q; - - fn set(&mut self, state: Q); - - fn map(self, f: F) -> Option - where - F: FnOnce(Q) -> U, - Self: Sized; + fn apply(self, f: F) -> Self::Output where F: FnOnce(Q) -> R; } /* @@ -74,11 +61,11 @@ macro_rules! impl_raw_state { seal!(); - fn into_inner(self) -> Q { + fn get(self) -> Q { self.$($field)* } - fn get(&self) -> &Q { + fn get_ref(&self) -> &Q { &self.$($field)* } @@ -102,3 +89,4 @@ impl_raw_state! { Halt(0), State(0), } + diff --git a/core/src/state/states/binary.rs b/core/src/state/states/binary.rs deleted file mode 100644 index 939ced3..0000000 --- a/core/src/state/states/binary.rs +++ /dev/null @@ -1,154 +0,0 @@ -/* - Appellation: state - Contrib: FL03 -*/ -use crate::State; - -#[derive( - Clone, - Copy, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - strum::EnumDiscriminants, - strum::EnumIs, - strum::VariantNames, -)] -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize, serde::Serialize), - serde(rename_all = "lowercase"), - strum_discriminants( - derive(serde::Deserialize, serde::Serialize), - serde(rename_all = "lowercase") - ) -)] -#[repr(C)] -#[strum(serialize_all = "lowercase")] -#[strum_discriminants( - name(BinState), - derive( - Hash, - Ord, - PartialOrd, - strum::AsRefStr, - strum::Display, - strum::EnumCount, - strum::EnumIs, - strum::EnumIter, - strum::EnumString, - strum::VariantNames - ) -)] -pub enum BinaryState { - Invalid(I), - Valid(V), -} - -impl BinaryState { - pub fn invalid(state: I) -> Self { - Self::Invalid(state) - } - - pub fn valid(state: V) -> Self { - Self::Valid(state) - } - - pub fn invalidate(self, state: Q) -> BinaryState { - match self { - Self::Invalid(_) => BinaryState::Invalid(state), - Self::Valid(_) => BinaryState::Invalid(state), - } - } - - pub fn kind(&self) -> BinState { - match self { - Self::Invalid(_) => BinState::Invalid, - Self::Valid(_) => BinState::Valid, - } - } -} - -impl BinaryState { - pub fn into_inner(self) -> State { - match self { - Self::Invalid(q) => State(q), - Self::Valid(q) => State(q), - } - } - - pub fn state(&self) -> (BinState, &Q) { - (self.kind(), self.as_ref()) - } -} - -impl AsRef for BinaryState { - fn as_ref(&self) -> &Q { - match self { - Self::Invalid(q) => q, - Self::Valid(q) => q, - } - } -} - -impl AsMut for BinaryState { - fn as_mut(&mut self) -> &mut Q { - match self { - Self::Invalid(q) => q, - Self::Valid(q) => q, - } - } -} - -impl core::borrow::Borrow for BinaryState { - fn borrow(&self) -> &Q { - self.as_ref() - } -} - -impl core::borrow::BorrowMut for BinaryState { - fn borrow_mut(&mut self) -> &mut Q { - self.as_mut() - } -} - -impl Default for BinState { - fn default() -> Self { - Self::Invalid - } -} - -impl Default for BinaryState -where - I: Default, -{ - fn default() -> Self { - Self::invalid(::default()) - } -} - -impl core::ops::Deref for BinaryState { - type Target = Q; - - fn deref(&self) -> &Self::Target { - self.as_ref() - } -} - -impl core::ops::DerefMut for BinaryState { - fn deref_mut(&mut self) -> &mut Self::Target { - self.as_mut() - } -} - -impl core::fmt::Display for BinaryState -where - Q: core::fmt::Display, -{ - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{}", *self) - } -} From 02c61950d57390d4608b3429ba5b3b21c7389b7e Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sun, 1 Sep 2024 23:30:16 -0500 Subject: [PATCH 18/27] update Signed-off-by: Joe McCain III --- core/src/actors/engine.rs | 6 +++--- core/src/actors/exec.rs | 2 +- core/src/rules/mod.rs | 6 +++--- core/src/rules/rule.rs | 2 +- core/src/state/halt/mod.rs | 2 +- core/src/state/impls/impl_ops.rs | 5 ++++- core/src/state/mod.rs | 5 +++-- core/src/state/state.rs | 2 +- core/src/tape/mod.rs | 2 +- core/src/tape/tape.rs | 6 ++++++ core/src/types/head.rs | 2 +- core/src/types/tail.rs | 2 +- core/tests/actor.rs | 2 +- core/tests/state.rs | 2 +- 14 files changed, 28 insertions(+), 18 deletions(-) diff --git a/core/src/actors/engine.rs b/core/src/actors/engine.rs index 44eac2d..924b962 100644 --- a/core/src/actors/engine.rs +++ b/core/src/actors/engine.rs @@ -72,7 +72,7 @@ where core::mem::replace(&mut self.scope, next); } - pub fn process(&mut self) -> Result<(), Error> + pub fn process(&mut self) -> Result<(), Error> where A: crate::Symbolic, Q: Clone + Eq + std::hash::Hash, @@ -83,8 +83,8 @@ where None => return Err(Error::runtime_error("Engine::process")), }; - if let Some(rule) = self.program.get(self.scope.state(), &symbol) { - self.handle(rule.direction, rule.state.clone(), rule.symbol.clone()); + if let Some(rule) = self.program.get(self.scope.state(), symbol) { + self.handle(rule.direction, rule.state.clone(), rule.symbol); } Ok(()) diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 5a6db9c..79faf87 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -104,7 +104,7 @@ where // process the instruction self.actor.process(tail.clone()); // return the head - return Some(tail.into_head()); + Some(tail.into_head()) } else { #[cfg(feature = "tracing")] tracing::error!("No symbol found at {}", self.actor.position()); diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index 213828d..37557ea 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -124,7 +124,7 @@ impl Scope for Rule { } fn symbol(&self) -> &S { - &self.symbol() + self.symbol() } } @@ -138,7 +138,7 @@ impl Directive for Rule { } fn value(&self) -> &S { - &self.write_symbol() + self.write_symbol() } } @@ -162,7 +162,7 @@ impl Directive for crate::Tail { } fn value(&self) -> &S { - &self.symbol() + self.symbol() } } diff --git a/core/src/rules/rule.rs b/core/src/rules/rule.rs index eed4776..364ee28 100644 --- a/core/src/rules/rule.rs +++ b/core/src/rules/rule.rs @@ -157,7 +157,7 @@ mod impls { S: PartialEq, { fn eq(&self, other: &(Head, Tail)) -> bool { - &self.head == &other.0 && &self.tail == &other.1 + self.head == other.0 && self.tail == other.1 } } diff --git a/core/src/state/halt/mod.rs b/core/src/state/halt/mod.rs index fc30cd1..70bab1c 100644 --- a/core/src/state/halt/mod.rs +++ b/core/src/state/halt/mod.rs @@ -35,7 +35,7 @@ pub trait HaltableExt: Haltable { F: FnOnce(Q) -> U, Self: Sized, { - self.get().map(|state| f(state)) + self.get().map(f) } } diff --git a/core/src/state/impls/impl_ops.rs b/core/src/state/impls/impl_ops.rs index 1bbfd8b..ce64f0a 100644 --- a/core/src/state/impls/impl_ops.rs +++ b/core/src/state/impls/impl_ops.rs @@ -48,7 +48,10 @@ where } } -impl num::traits::Num for State where Q: num::traits::Num { +impl num::traits::Num for State +where + Q: num::traits::Num, +{ type FromStrRadixErr = Q::FromStrRadixErr; fn from_str_radix(str: &str, radix: u32) -> Result { diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index 910c202..7105567 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -48,7 +48,9 @@ pub trait RawState { pub trait Apply { type Output; - fn apply(self, f: F) -> Self::Output where F: FnOnce(Q) -> R; + fn apply(self, f: F) -> Self::Output + where + F: FnOnce(Q) -> R; } /* @@ -89,4 +91,3 @@ impl_raw_state! { Halt(0), State(0), } - diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 0d64ca8..ebffb22 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -25,7 +25,7 @@ impl State { } /// Casts the state to a new type, returning a new instance of [State]. /// - /// ### Saftey + /// # Saftey /// /// * pub unsafe fn cast(self) -> State { diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index 0887f1b..78314ee 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -100,7 +100,7 @@ where } fn get_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value> { - HashMap::get_mut(self, &key) + HashMap::get_mut(self, key) } fn insert(&mut self, key: Self::Key, value: Self::Value) { diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index 2bf1c58..dd41cf9 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -29,6 +29,12 @@ pub struct StdTape { ticks: Cell, } +impl Default for StdTape { + fn default() -> Self { + Self::new() + } +} + impl StdTape { pub fn new() -> Self { StdTape { diff --git a/core/src/types/head.rs b/core/src/types/head.rs index afe2e2f..13e93f6 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -293,7 +293,7 @@ where S: PartialEq, { fn eq(&self, head: &Head) -> bool { - &head.state == &self.0 && &head.symbol == &self.1 + head.state == self.0 && head.symbol == self.1 } } diff --git a/core/src/types/tail.rs b/core/src/types/tail.rs index 308712a..d9dfa72 100644 --- a/core/src/types/tail.rs +++ b/core/src/types/tail.rs @@ -67,7 +67,7 @@ impl Tail { } /// 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> { + pub fn to_head_ref(&self) -> Head<&Q, &S> { super::Head::new(self.state.to_ref(), &self.symbol) } diff --git a/core/tests/actor.rs b/core/tests/actor.rs index 3f2bc54..3380b0f 100644 --- a/core/tests/actor.rs +++ b/core/tests/actor.rs @@ -25,7 +25,7 @@ fn busy_beaver() { let initial_state = State(0_isize); let input = [0_usize; 10]; - let program = Program::from_iter(RULES.clone()); + let program = Program::from_iter(*RULES); let actor = Actor::from_state(initial_state).with_alpha(input); let mut rt = actor.execute(program); diff --git a/core/tests/state.rs b/core/tests/state.rs index 27b68db..0e69d8f 100644 --- a/core/tests/state.rs +++ b/core/tests/state.rs @@ -91,4 +91,4 @@ fn numstate() { assert_eq!(one, 1); // verify the state has an inner value of 0 assert_eq!(zero, 0.0); -} \ No newline at end of file +} From 0d56caf24bca44eb57ac69378e93a1de4478bb2a Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 2 Sep 2024 06:21:10 -0500 Subject: [PATCH 19/27] update Signed-off-by: Joe McCain III --- README.md | 25 ++++++++++++++++--------- core/src/actors/engine.rs | 6 +++--- core/src/tape/mod.rs | 18 ++++++++++++++++++ core/src/types/mod.rs | 3 +++ core/src/types/snapshot.rs | 14 ++++++++++++++ 5 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 core/src/types/snapshot.rs diff --git a/README.md b/README.md index 273adcb..98fc100 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ _**The library is currently in the early stages of development and is still settling in on a feel for the api.**_ -This library focuses on building concrete implementations for Turing Machines. +Welcome to `rstm`! This crate provides a simple and easy-to-use interface for creating and executing Turing machines. The crate is designed to be flexible and extensible, allowing developers to create and execute a wide range of Turing machines. Furthermore, the crate focuses on efficiency and leverages feature-gating to reduce overhead. ## Getting Started @@ -36,7 +36,14 @@ cargo run -f F --example {actor} ## Usage -### Creating a new ruleset +### Rulesets + +To faciliate the creation of rules for the machine, the crate provides a `ruleset!` macro. The macro mimics the +structure of the transition function $\delta$ defined by "On topological dynamics of Turing machines" by Petr Kůrka. + +$$\delta : Q\times{A}\rarr{Q\times{A}\times{(0, \pm{1})}}$$ + +The syntax of the macro is as follows: ```rust ruleset![ @@ -45,20 +52,20 @@ cargo run -f F --example {actor} ] ``` -Programs are essentially collections of rules that define the behavior of the machine. Facilitating the creation of these rules is the `ruleset!` macro. The macro allows developers to define a set of rules for the machine in a concise and readable manner while further emulating the transition function $\delta$ defined by "On topological dynamics of Turing machines" by Petr Kůrka: - -$$ -\delta: Q \times A \rarr Q\times{A}\times{\bigl\{0, \pm{1}\bigr\}}. -$$ - The macro expands into a `Vec` where `Rule` is structure consisting of two other structures, namely: `Head` and the `Tail`. Each of these structures is a direct representation of the two sides of the transition function defined above +#### _Rules_ + ```rust pub struct Rule { pub head: Head, pub tail: Tail, } +``` +where `Head` and `Tail` are defined as follows: + +```rust pub struct Head { pub state: Q, pub symbol: S, @@ -73,7 +80,7 @@ The macro expands into a `Vec` where `Rule` is structure consisting of two **Note:** the macro is hygenic, meaning developers will not need to import the `Direction` enum nor its variants in order to use the macro. -#### _Example_ +#### _Example usage_ The following example demonstrates the use of the `ruleset!` macro to define a set of rules for a three-state, two-symbol Turing machine. diff --git a/core/src/actors/engine.rs b/core/src/actors/engine.rs index 924b962..d7278cf 100644 --- a/core/src/actors/engine.rs +++ b/core/src/actors/engine.rs @@ -64,12 +64,12 @@ where self.tape.insert(self.position(), data) } - fn handle(&mut self, direction: Direction, state: State, symbol: A) { + fn handle(&mut self, direction: Direction, state: State, symbol: A) -> Head { let next = Head { state, symbol: self.position() + direction, }; - core::mem::replace(&mut self.scope, next); + core::mem::replace(&mut self.scope, next) } pub fn process(&mut self) -> Result<(), Error> @@ -84,7 +84,7 @@ where }; if let Some(rule) = self.program.get(self.scope.state(), symbol) { - self.handle(rule.direction, rule.state.clone(), rule.symbol); + let prev = self.handle(rule.direction, rule.state.clone(), rule.symbol); } Ok(()) diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index 78314ee..a40f737 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -38,6 +38,24 @@ pub trait Mem { fn len(&self) -> usize; } +#[doc(hidden)] +pub trait Tape { + type Index; + type Elem; + + fn clear(&mut self); + + fn get(&self, index: &Self::Index) -> Option<&A>; + + fn get_mut(&mut self, index: &Self::Index) -> Option<&mut A>; + + fn insert(&mut self, index: Self::Index, symbol: A); + + fn is_empty(&self) -> bool; + + fn len(&self) -> usize; +} + /* ************* Implementations ************* */ diff --git a/core/src/types/mod.rs b/core/src/types/mod.rs index 0dfc9cc..e425f15 100644 --- a/core/src/types/mod.rs +++ b/core/src/types/mod.rs @@ -9,6 +9,9 @@ pub(crate) mod direction; pub(crate) mod head; pub(crate) mod tail; +#[doc(hidden)] +pub mod snapshot; + pub(crate) mod prelude { pub use super::direction::*; pub use super::head::Head; diff --git a/core/src/types/snapshot.rs b/core/src/types/snapshot.rs new file mode 100644 index 0000000..012ad76 --- /dev/null +++ b/core/src/types/snapshot.rs @@ -0,0 +1,14 @@ +/* + Appellation: snapshot + Contrib: FL03 +*/ +use crate::{Alphabet, Head}; + +pub struct Snapshot +where + S: Alphabet, +{ + pub index: isize, + pub head: Head, + pub tape: S, +} From e1a5484e44d2179b9f4ccbf746cf6543e2d39cc5 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 2 Sep 2024 06:33:26 -0500 Subject: [PATCH 20/27] update Signed-off-by: Joe McCain III --- core/src/rules/rule.rs | 2 +- core/src/types/header.rs | 46 ++++++++++++++++++++++++++++++++++++++++ core/src/types/mod.rs | 2 ++ core/src/types/tail.rs | 2 +- 4 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 core/src/types/header.rs diff --git a/core/src/rules/rule.rs b/core/src/rules/rule.rs index 364ee28..6848f07 100644 --- a/core/src/rules/rule.rs +++ b/core/src/rules/rule.rs @@ -55,7 +55,7 @@ impl Rule { } /// Returns the next [Head] of the system pub fn next_head(&self) -> Head<&'_ Q, &'_ A> { - self.tail().to_head_ref() + self.tail().as_head_ref() } /// Consumes the current object and returns the next [Head] of the system pub fn into_next_head(self) -> Head { diff --git a/core/src/types/header.rs b/core/src/types/header.rs new file mode 100644 index 0000000..a69518f --- /dev/null +++ b/core/src/types/header.rs @@ -0,0 +1,46 @@ +/* + Appellation: header + Contrib: FL03 +*/ +use super::{Direction, Head}; +use crate::State; + +pub struct Tail { + pub direction: Direction, + pub head: Head, +} + +impl Tail { + pub fn new(direction: Direction, state: State, symbol: S) -> Self { + Self { + direction, + head: Head::new(state, symbol), + } + } + + pub fn as_head_ref(&self) -> Head<&Q, &S> { + self.head.to_ref() + } + + pub fn state(&self) -> State<&'_ Q> { + self.head.state() + } + + pub fn symbol(&self) -> &S { + self.head.symbol() + } + + pub fn to_ref(&self) -> Tail<&'_ Q, &'_ S> { + Tail { + direction: self.direction, + head: self.head.to_ref(), + } + } + + pub fn to_mut(&mut self) -> Tail<&'_ mut Q, &'_ mut S> { + Tail { + direction: self.direction, + head: self.head.to_mut(), + } + } +} diff --git a/core/src/types/mod.rs b/core/src/types/mod.rs index e425f15..2f5d369 100644 --- a/core/src/types/mod.rs +++ b/core/src/types/mod.rs @@ -9,6 +9,8 @@ pub(crate) mod direction; pub(crate) mod head; pub(crate) mod tail; +#[doc(hidden)] +pub mod header; #[doc(hidden)] pub mod snapshot; diff --git a/core/src/types/tail.rs b/core/src/types/tail.rs index d9dfa72..fb9122f 100644 --- a/core/src/types/tail.rs +++ b/core/src/types/tail.rs @@ -67,7 +67,7 @@ impl Tail { } /// Returns an instance of the [head](Head) where each element within /// the created instance is an immutable reference - pub fn to_head_ref(&self) -> Head<&Q, &S> { + pub fn as_head_ref(&self) -> Head<&Q, &S> { super::Head::new(self.state.to_ref(), &self.symbol) } From d1971b708f7be2b212c4beee0b69e7b0184942bb Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 2 Sep 2024 07:05:18 -0500 Subject: [PATCH 21/27] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 41 ++++----- core/src/actors/engine.rs | 32 ++++--- core/src/actors/exec.rs | 15 +++- core/src/rules/rule.rs | 2 +- core/src/types/cell.rs | 23 +++++ core/src/types/header.rs | 46 ---------- core/src/types/mod.rs | 4 +- core/src/types/snapshot.rs | 14 --- core/src/types/tail.rs | 12 ++- core/src/types/transition.rs | 162 +++++++++++++++++++++++++++++++++++ 10 files changed, 248 insertions(+), 103 deletions(-) create mode 100644 core/src/types/cell.rs delete mode 100644 core/src/types/header.rs delete mode 100644 core/src/types/snapshot.rs create mode 100644 core/src/types/transition.rs diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 4a1ae2f..426e504 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -4,21 +4,24 @@ */ use super::Executor; use crate::rules::Program; -use crate::{Direction, Error, Head, State, Tail}; +use crate::{Direction, Error, Head, State}; -/// An [Actor] describes a Turing machine with a moving head (TMH). +/// An [Actor] is an implementation of a Turing machine with a moving head (TMH). /// -/// [Actor]'s abstractly define actionable surfaces capable of executing a [Program]. +/// The model contains the following components: +/// +/// - `alpha`: the input alphabet +/// - `head`: the head of the tape #[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd)] -pub struct Actor { +pub struct Actor { /// the input alphabet - pub(crate) alpha: Vec, + pub(crate) alpha: Vec, /// the head of the tape pub(crate) head: Head, } -impl Actor { - pub fn new(alpha: impl IntoIterator, state: State, symbol: usize) -> Self { +impl Actor { + pub fn new(alpha: impl IntoIterator, state: State, symbol: usize) -> Self { Self { alpha: Vec::from_iter(alpha), head: Head { state, symbol }, @@ -35,7 +38,7 @@ impl Actor { /// Consumes the current instance and returns a new instance with the given alphabet pub fn with_alpha(self, alpha: I) -> Self where - I: IntoIterator, + I: IntoIterator, { Self { alpha: Vec::from_iter(alpha), @@ -64,11 +67,11 @@ impl Actor { } } /// Returns an immutable reference to the tape, as a slice - pub fn alpha(&self) -> &[S] { + pub fn alpha(&self) -> &[A] { &self.alpha } /// Returns a mutable reference of the tape as a slice - pub fn alpha_mut(&mut self) -> &mut [S] { + pub fn alpha_mut(&mut self) -> &mut [A] { &mut self.alpha } /// Returns an immutable reference to the head of the tape @@ -101,7 +104,7 @@ impl Actor { } /// Executes the given program; the method is lazy, meaning it will not compute immediately /// but will return an [Executor] that is better suited for managing the runtime. - pub fn execute(self, program: Program) -> Executor { + pub fn execute(self, program: Program) -> Executor { Executor::new(self, program) } /// Checks if the tape is empty @@ -125,7 +128,7 @@ impl Actor { feature = "tracing", tracing::instrument(skip_all, name = "read", target = "actor") )] - pub fn read(&self) -> Result, Error> { + pub fn read(&self) -> Result, Error> { #[cfg(feature = "tracing")] tracing::trace!("Reading the tape..."); self.alpha @@ -142,7 +145,7 @@ impl Actor { feature = "tracing", tracing::instrument(skip_all, name = "write", target = "actor") )] - pub fn write(&mut self, value: S) { + pub fn write(&mut self, value: A) { #[cfg(feature = "tracing")] tracing::trace!("Writing to the tape..."); let pos = self.position(); @@ -161,16 +164,18 @@ impl Actor { self.alpha[pos] = value; } } - /// Performs a single step of the Turing machine; returns the previous head of the tape + /// Performs a single step of the Turing machine; returns the previous head of the tape. + /// Each step writes the given symbol to the tape, updates the state of the head, and moves + /// the head by a single unit in the specified direction. #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "handle", target = "actor") )] - pub(crate) fn handle( + pub(crate) fn step( &mut self, direction: Direction, state: State, - symbol: S, + symbol: A, ) -> Head { #[cfg(feature = "tracing")] tracing::trace!("Transitioning the actor..."); @@ -179,10 +184,6 @@ impl Actor { // update the head of the actor self.head.replace(state, self.position() + direction) } - - pub(crate) fn process(&mut self, rule: Tail) -> Head { - self.handle(rule.direction, rule.state, rule.symbol) - } } impl core::fmt::Debug for Actor diff --git a/core/src/actors/engine.rs b/core/src/actors/engine.rs index d7278cf..0d8ab36 100644 --- a/core/src/actors/engine.rs +++ b/core/src/actors/engine.rs @@ -44,6 +44,10 @@ where Self { program, ..self } } + pub fn current_state(&self) -> State<&'_ Q> { + self.scope.state() + } + pub fn position(&self) -> isize { self.scope.symbol } @@ -56,20 +60,23 @@ where self.tape.entry(self.position()) } - pub fn read(&self) -> Option<&A> { - self.tape.get(&self.scope.symbol) + pub fn read(&self) -> Option> { + self.tape.get(&self.scope.symbol).map(|symbol| Head { + state: self.scope.state(), + symbol, + }) } pub fn write(&mut self, data: A) -> Option { self.tape.insert(self.position(), data) } - + /// Handle the given rule; writes the symbol onto the tape before updating the state of the + /// head and applying a single step in the direction specified. Returns the previous head. fn handle(&mut self, direction: Direction, state: State, symbol: A) -> Head { - let next = Head { - state, - symbol: self.position() + direction, - }; - core::mem::replace(&mut self.scope, next) + // write the symbol onto the tape + let _prev = self.write(symbol); + // replace the current head with the new head + self.scope.replace(state, self.position() + direction) } pub fn process(&mut self) -> Result<(), Error> @@ -77,14 +84,13 @@ where A: crate::Symbolic, Q: Clone + Eq + std::hash::Hash, { - let scope = self.cell(); - let symbol = match self.read() { - Some(symbol) => symbol, + let Head { state, symbol } = match self.read() { + Some(head) => head, None => return Err(Error::runtime_error("Engine::process")), }; - if let Some(rule) = self.program.get(self.scope.state(), symbol) { - let prev = self.handle(rule.direction, rule.state.clone(), rule.symbol); + if let Some(rule) = self.program.get(state, symbol) { + let _prev = self.handle(rule.direction, rule.state.clone(), rule.symbol); } Ok(()) diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 79faf87..c34c0d7 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ use super::Actor; -use crate::{Error, Head, Program, Symbolic}; +use crate::{Error, Head, Program, State, Symbolic}; /// pub struct Executor { @@ -43,6 +43,10 @@ impl Executor { pub const fn actor(&self) -> &Actor { &self.actor } + + pub fn current_state(&self) -> State<&'_ Q> { + self.actor.state() + } /// Reads the current symbol at the head of the tape pub fn read(&self) -> Result, Error> { self.actor.read() @@ -100,11 +104,14 @@ where } }; // execute the program - if let Some(tail) = self.program.get(head.state, head.symbol).cloned() { + if let Some(tail) = self.program.get(head.state, head.symbol) { + let next = tail.as_head().cloned(); // process the instruction - self.actor.process(tail.clone()); + let _prev = self + .actor + .step(tail.direction, tail.state.clone(), tail.symbol); // return the head - Some(tail.into_head()) + Some(next) } else { #[cfg(feature = "tracing")] tracing::error!("No symbol found at {}", self.actor.position()); diff --git a/core/src/rules/rule.rs b/core/src/rules/rule.rs index 6848f07..37c8530 100644 --- a/core/src/rules/rule.rs +++ b/core/src/rules/rule.rs @@ -55,7 +55,7 @@ impl Rule { } /// Returns the next [Head] of the system pub fn next_head(&self) -> Head<&'_ Q, &'_ A> { - self.tail().as_head_ref() + self.tail().as_head() } /// Consumes the current object and returns the next [Head] of the system pub fn into_next_head(self) -> Head { diff --git a/core/src/types/cell.rs b/core/src/types/cell.rs new file mode 100644 index 0000000..bf0226b --- /dev/null +++ b/core/src/types/cell.rs @@ -0,0 +1,23 @@ +/* + Appellation: cell + Contrib: FL03 +*/ +use crate::{Alphabet, Head, State}; + +pub struct Cell +where + S: Alphabet, +{ + pub index: isize, + pub state: State<*const Q>, + pub symbol: *const S::Elem, +} + +pub struct Snapshot +where + S: Alphabet, +{ + pub index: isize, + pub head: Head, + pub tape: S, +} diff --git a/core/src/types/header.rs b/core/src/types/header.rs deleted file mode 100644 index a69518f..0000000 --- a/core/src/types/header.rs +++ /dev/null @@ -1,46 +0,0 @@ -/* - Appellation: header - Contrib: FL03 -*/ -use super::{Direction, Head}; -use crate::State; - -pub struct Tail { - pub direction: Direction, - pub head: Head, -} - -impl Tail { - pub fn new(direction: Direction, state: State, symbol: S) -> Self { - Self { - direction, - head: Head::new(state, symbol), - } - } - - pub fn as_head_ref(&self) -> Head<&Q, &S> { - self.head.to_ref() - } - - pub fn state(&self) -> State<&'_ Q> { - self.head.state() - } - - pub fn symbol(&self) -> &S { - self.head.symbol() - } - - pub fn to_ref(&self) -> Tail<&'_ Q, &'_ S> { - Tail { - direction: self.direction, - head: self.head.to_ref(), - } - } - - pub fn to_mut(&mut self) -> Tail<&'_ mut Q, &'_ mut S> { - Tail { - direction: self.direction, - head: self.head.to_mut(), - } - } -} diff --git a/core/src/types/mod.rs b/core/src/types/mod.rs index 2f5d369..354b39c 100644 --- a/core/src/types/mod.rs +++ b/core/src/types/mod.rs @@ -10,9 +10,9 @@ pub(crate) mod head; pub(crate) mod tail; #[doc(hidden)] -pub mod header; +pub mod cell; #[doc(hidden)] -pub mod snapshot; +pub mod transition; pub(crate) mod prelude { pub use super::direction::*; diff --git a/core/src/types/snapshot.rs b/core/src/types/snapshot.rs deleted file mode 100644 index 012ad76..0000000 --- a/core/src/types/snapshot.rs +++ /dev/null @@ -1,14 +0,0 @@ -/* - Appellation: snapshot - Contrib: FL03 -*/ -use crate::{Alphabet, Head}; - -pub struct Snapshot -where - S: Alphabet, -{ - pub index: isize, - pub head: Head, - pub tape: S, -} diff --git a/core/src/types/tail.rs b/core/src/types/tail.rs index fb9122f..3b155da 100644 --- a/core/src/types/tail.rs +++ b/core/src/types/tail.rs @@ -63,12 +63,18 @@ impl Tail { } /// Consumes the tail and returns a new instance of the [Head] pub fn into_head(self) -> Head { - super::Head::new(self.state, self.symbol) + Head { + state: self.state, + symbol: self.symbol, + } } /// Returns an instance of the [head](Head) where each element within /// the created instance is an immutable reference - pub fn as_head_ref(&self) -> Head<&Q, &S> { - super::Head::new(self.state.to_ref(), &self.symbol) + pub fn as_head(&self) -> Head<&Q, &S> { + Head { + state: self.state.to_ref(), + symbol: &self.symbol, + } } pub fn to_ref(&self) -> Tail<&'_ Q, &'_ S> { diff --git a/core/src/types/transition.rs b/core/src/types/transition.rs new file mode 100644 index 0000000..9a3a42e --- /dev/null +++ b/core/src/types/transition.rs @@ -0,0 +1,162 @@ +/* + Appellation: transition + Contrib: FL03 +*/ +use super::{Direction, Head}; +use crate::State; + +#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(rename_all = "lowercase") +)] +pub struct Transition { + pub direction: Direction, + pub head: Head, +} + +impl Transition { + pub fn new(direction: Direction, state: State, symbol: S) -> Self { + Self { + direction, + head: Head::new(state, symbol), + } + } + + pub fn with_direction(self, direction: Direction) -> Self { + Self { direction, ..self } + } + + pub fn with_state(self, state: State) -> Self { + Self { + head: self.head.with_state(state), + ..self + } + } + + pub fn with_symbol(self, symbol: S) -> Self { + Self { + head: self.head.with_symbol(symbol), + ..self + } + } + + pub fn as_head_ref(&self) -> Head<&Q, &S> { + self.head.to_ref() + } + + pub fn as_mut_head(&mut self) -> Head<&mut Q, &mut S> { + self.head.to_mut() + } + + pub const fn head(&self) -> &Head { + &self.head + } + + pub fn head_mut(&mut self) -> &mut Head { + &mut self.head + } + + pub fn state(&self) -> State<&'_ Q> { + self.head.state() + } + + pub fn state_mut(&mut self) -> State<&'_ mut Q> { + self.head.state_mut() + } + + pub fn symbol(&self) -> &S { + self.head.symbol() + } + + pub fn symbol_mut(&mut self) -> &mut S { + self.head.symbol_mut() + } + + pub fn to_ref(&self) -> Transition<&'_ Q, &'_ S> { + Transition { + direction: self.direction, + head: self.head.to_ref(), + } + } + + pub fn to_mut(&mut self) -> Transition<&'_ mut Q, &'_ mut S> { + Transition { + direction: self.direction, + head: self.head.to_mut(), + } + } +} + +impl<'a, Q, S> Transition<&'a Q, &'a S> { + pub fn cloned(&self) -> Transition + where + Q: Clone, + S: Clone, + { + Transition { + direction: self.direction, + head: self.head.cloned(), + } + } + + pub fn copied(&self) -> Transition + where + Q: Copy, + S: Copy, + { + Transition { + direction: self.direction, + head: self.head.copied(), + } + } +} + +impl<'a, Q, S> Transition<&'a mut Q, &'a mut S> { + pub fn cloned(&self) -> Transition + where + Q: Clone, + S: Clone, + { + Transition { + direction: self.direction, + head: self.head.cloned(), + } + } + + pub fn copied(&self) -> Transition + where + Q: Copy, + S: Copy, + { + Transition { + direction: self.direction, + head: self.head.copied(), + } + } +} + +impl core::fmt::Debug for Transition +where + Q: core::fmt::Debug, + S: core::fmt::Debug, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("Transition") + .field(&self.direction) + .field(&self.head.state) + .field(&self.head.symbol) + .finish() + } +} + +impl core::fmt::Display for Transition +where + Q: core::fmt::Display, + S: core::fmt::Display, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{dir}({head})", dir = self.direction, head = self.head) + } +} From b9ef8d86e55ea4b7ad4b554f15ff8bed1e26652e Mon Sep 17 00:00:00 2001 From: Joe McCain III <92560746+FL03@users.noreply.github.com> Date: Mon, 2 Sep 2024 08:45:12 -0500 Subject: [PATCH 22/27] Update rust.yml --- .github/workflows/rust.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 306d0cc..2b72ebc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -11,7 +11,6 @@ env: on: pull_request: branches: [ main, v*.*.* ] - branches-ignore: [ *-beta, *-dev, *-nightly ] release: types: [ created ] repository_dispatch: From 953a086ccb56a3c9ce6419658428153b3538dee2 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Tue, 3 Sep 2024 07:12:23 -0500 Subject: [PATCH 23/27] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 59 ++++--- core/src/actors/exec.rs | 10 +- core/src/actors/mod.rs | 4 - core/src/lib.rs | 2 +- core/src/rules/mod.rs | 152 +++++++++++++----- core/src/rules/program.rs | 34 ++-- core/src/rules/ruleset.rs | 26 +-- core/src/state/impls/impl_repr.rs | 18 +++ core/src/tape/hash_tape.rs | 28 ++-- core/src/tape/mod.rs | 92 ++++++++--- core/src/tape/tape.rs | 28 ++-- core/src/traits/mod.rs | 2 + core/src/traits/transform.rs | 58 +++++++ core/src/types/cell.rs | 26 +-- core/src/types/head.rs | 19 +-- core/src/types/tail.rs | 32 +++- core/src/types/transition.rs | 5 + core/tests/actor.rs | 4 +- core/tests/rules.rs | 4 +- rstm/Cargo.toml | 17 +- rstm/examples/actor.rs | 4 +- rstm/src/models/base.rs | 8 +- .../src/actors => rstm/src/models}/engine.rs | 38 +++-- rstm/src/models/mod.rs | 1 + 24 files changed, 450 insertions(+), 221 deletions(-) create mode 100644 core/src/traits/transform.rs rename {core/src/actors => rstm/src/models}/engine.rs (78%) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 426e504..34d5ad1 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ use super::Executor; -use crate::rules::Program; +use crate::rules::Ruleset; use crate::{Direction, Error, Head, State}; /// An [Actor] is an implementation of a Turing machine with a moving head (TMH). @@ -14,25 +14,25 @@ use crate::{Direction, Error, Head, State}; /// - `head`: the head of the tape #[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd)] pub struct Actor { - /// the input alphabet - pub(crate) alpha: Vec, /// the head of the tape pub(crate) head: Head, + /// the input alphabet + pub(crate) tape: Vec, } impl Actor { pub fn new(alpha: impl IntoIterator, state: State, symbol: usize) -> Self { Self { - alpha: Vec::from_iter(alpha), head: Head { state, symbol }, + tape: Vec::from_iter(alpha), } } /// Constructs a new [Actor] with the given state; assumes the tape is empty and the head /// is located at `0`. pub fn from_state(state: State) -> Self { Self { - alpha: Vec::new(), head: Head { state, symbol: 0 }, + tape: Vec::new(), } } /// Consumes the current instance and returns a new instance with the given alphabet @@ -41,7 +41,7 @@ impl Actor { I: IntoIterator, { Self { - alpha: Vec::from_iter(alpha), + tape: Vec::from_iter(alpha), ..self } } @@ -67,12 +67,12 @@ impl Actor { } } /// Returns an immutable reference to the tape, as a slice - pub fn alpha(&self) -> &[A] { - &self.alpha + pub fn tape(&self) -> &[A] { + &self.tape } /// Returns a mutable reference of the tape as a slice - pub fn alpha_mut(&mut self) -> &mut [A] { - &mut self.alpha + pub fn tape_mu(&mut self) -> &mut [A] { + &mut self.tape } /// Returns an immutable reference to the head of the tape pub const fn head(&self) -> &Head { @@ -92,24 +92,24 @@ impl Actor { } /// Returns the current position of the head on the tape pub fn position(&self) -> usize { - self.head.symbol + self.head().symbol } /// Returns an instance of the state with an immutable reference to the inner value pub fn state(&self) -> State<&Q> { - self.head.state() + self.head().state() } /// Returns an instance of the state with a mutable reference to the inner value pub fn state_mut(&mut self) -> State<&mut Q> { - self.head.state_mut() + self.head_mut().state_mut() } /// Executes the given program; the method is lazy, meaning it will not compute immediately /// but will return an [Executor] that is better suited for managing the runtime. - pub fn execute(self, program: Program) -> Executor { + pub fn execute(self, program: Ruleset) -> Executor { Executor::new(self, program) } /// Checks if the tape is empty pub fn is_empty(&self) -> bool { - self.alpha.is_empty() + self.tape.is_empty() } /// Checks if the tape is halted pub fn is_halted(&self) -> bool @@ -121,20 +121,20 @@ impl Actor { /// Returns the length of the tape #[inline] pub fn len(&self) -> usize { - self.alpha.len() + self.tape.len() } /// Reads the current symbol at the head of the tape #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "read", target = "actor") )] - pub fn read(&self) -> Result, Error> { + pub fn read(&self) -> Result, Error> { #[cfg(feature = "tracing")] tracing::trace!("Reading the tape..."); - self.alpha + self.tape .get(self.position()) .map(|symbol| Head { - state: self.head.state(), + state: self.state(), symbol, }) .ok_or(Error::index_out_of_bounds(self.position(), self.len())) @@ -154,14 +154,14 @@ impl Actor { #[cfg(feature = "tracing")] tracing::trace!("Prepending to the tape..."); // prepend to the tape - self.alpha.insert(0, value); + self.tape.insert(0, value); } else if pos >= self.len() { #[cfg(feature = "tracing")] tracing::trace!("Appending to the tape..."); // append to the tape - self.alpha.push(value); + self.tape.push(value); } else { - self.alpha[pos] = value; + self.tape[pos] = value; } } /// Performs a single step of the Turing machine; returns the previous head of the tape. @@ -186,12 +186,23 @@ impl Actor { } } +use crate::traits::transform::Handle; +use crate::Tail; + +impl Handle> for Actor { + type Output = Head; + + fn handle(&mut self, args: Tail) -> Self::Output { + self.step(args.direction, args.state, args.symbol) + } +} + impl core::fmt::Debug for Actor where S: core::fmt::Debug, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - for (i, c) in self.alpha.iter().enumerate() { + for (i, c) in self.tape.iter().enumerate() { if i == self.position() { write!(f, "[{c:?}]")?; } else { @@ -207,7 +218,7 @@ where S: core::fmt::Display, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - for (i, c) in self.alpha.iter().enumerate() { + for (i, c) in self.tape.iter().enumerate() { if i == self.position() { write!(f, "[{c}]")?; } else { diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index c34c0d7..5f7cc15 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -3,18 +3,18 @@ Contrib: FL03 */ use super::Actor; -use crate::{Error, Head, Program, State, Symbolic}; +use crate::{Error, Head, Ruleset, State, Symbolic}; /// pub struct Executor { pub(crate) actor: Actor, - pub(crate) program: Program, + pub(crate) program: Ruleset, /// the number of steps taken by the actor pub(crate) steps: usize, } impl Executor { - pub(crate) fn new(actor: Actor, program: Program) -> Self { + pub(crate) fn new(actor: Actor, program: Ruleset) -> Self { Self { actor, program, @@ -28,7 +28,7 @@ impl Executor { { Self { actor, - program: Program { + program: Ruleset { initial_state: Default::default(), rules: Vec::new(), }, @@ -36,7 +36,7 @@ impl Executor { } } /// Load a program into the executor - pub fn load(self, program: Program) -> Self { + pub fn load(self, program: Ruleset) -> Self { Executor { program, ..self } } diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs index 1b13ebe..7f24ae5 100644 --- a/core/src/actors/mod.rs +++ b/core/src/actors/mod.rs @@ -12,10 +12,6 @@ pub use self::{actor::Actor, exec::Executor}; pub(crate) mod actor; pub(crate) mod exec; -#[allow(unused)] -#[doc(hidden)] -mod engine; - pub(crate) mod prelude { pub use super::actor::Actor; pub use super::exec::Executor; diff --git a/core/src/lib.rs b/core/src/lib.rs index af2e4de..f78bc19 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -26,7 +26,7 @@ extern crate alloc; pub use self::{ actors::Actor, error::Error, - rules::{Program, Rule}, + rules::{Rule, Ruleset}, state::State, tape::StdTape, traits::prelude::*, diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index 37557ea..51d66a2 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{builders::RuleBuilder, program::Program, rule::Rule, ruleset::RuleSet}; +pub use self::{builders::RuleBuilder, program::Ruleset, rule::Rule, ruleset::RuleMap}; pub(crate) mod program; pub(crate) mod rule; @@ -17,24 +17,24 @@ mod builders { } pub(crate) mod prelude { - pub use super::program::Program; + pub use super::program::Ruleset; pub use super::rule::Rule; pub use super::{Directive, Scope, Transition}; } use crate::{Direction, Head, State, Symbolic, Tail}; -pub trait Rules { - type Key: Scope; - type Val: Directive; +pub trait Program { + type Key: Scope; + type Val: Directive; + + fn contains_key(&self, key: &Self::Key) -> bool; fn get(&self, key: &Self::Key) -> Option<&Self::Val>; fn insert(&mut self, key: Self::Key, val: Self::Val) -> Option; fn remove(&mut self, key: &Self::Key) -> Option; - - fn contains_key(&self, key: &Self::Key) -> bool; } pub trait Transition { @@ -76,7 +76,7 @@ pub trait Transition { pub trait Scope { fn current_state(&self) -> State<&'_ Q>; - fn symbol(&self) -> &S; + fn current_symbol(&self) -> &S; } /// [`Directive`] is a trait describing the `tail` of a typical Turing machine; @@ -85,12 +85,78 @@ pub trait Directive { fn next_state(&self) -> State<&'_ Q>; - fn value(&self) -> &S; + fn next_symbol(&self) -> &S; } /* ************* Implementations ************* */ +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +#[cfg(feature = "std")] +use std::collections::HashMap; + +#[cfg(feature = "alloc")] +impl Program for Vec> +where + Q: PartialEq, + A: PartialEq, +{ + type Key = Head; + type Val = Tail; + + fn contains_key(&self, key: &Head) -> bool { + self.iter().any(|rule| rule.head() == key) + } + + fn get(&self, key: &Head) -> Option<&Tail> { + self.iter().find_map(|rule| { + if rule.head() == key { + Some(rule.tail()) + } else { + None + } + }) + } + + fn insert(&mut self, key: Head, val: Tail) -> Option> { + self.iter_mut() + .find(|rule| rule.head() == &key) + .map(|rule| core::mem::replace(rule.tail_mut(), val)) + } + + fn remove(&mut self, key: &Head) -> Option> { + let index = self.iter().position(|rule| rule.head() == key)?; + Some(self.remove(index).tail) + } +} + +#[cfg(feature = "std")] +impl Program for HashMap, Tail> +where + Q: Eq + core::hash::Hash, + A: Eq + core::hash::Hash, +{ + type Key = Head; + type Val = Tail; + + fn contains_key(&self, key: &Head) -> bool { + self.contains_key(key) + } + + fn get(&self, key: &Head) -> Option<&Tail> { + self.get(key) + } + + fn insert(&mut self, key: Head, val: Tail) -> Option> { + self.insert(key, val) + } + + fn remove(&mut self, key: &Head) -> Option> { + self.remove(key) + } +} impl Transition for A where @@ -110,82 +176,82 @@ where } fn symbol(&self) -> &S { - self.symbol() + self.current_symbol() } fn write_symbol(&self) -> &S { - self.value() + self.next_symbol() } } -impl Scope for Rule { +impl Scope for (State, S) { fn current_state(&self) -> State<&'_ Q> { - self.head.state.to_ref() + self.0.to_ref() } - fn symbol(&self) -> &S { - self.symbol() + fn current_symbol(&self) -> &S { + &self.1 } } -impl Directive for Rule { - fn direction(&self) -> Direction { - self.direction() - } - - fn next_state(&self) -> State<&'_ Q> { - self.tail().state() +impl Scope for crate::Head { + fn current_state(&self) -> State<&'_ Q> { + self.state() } - fn value(&self) -> &S { - self.write_symbol() + fn current_symbol(&self) -> &S { + &self.symbol } } -impl Scope for crate::Head { +impl Scope for Rule { fn current_state(&self) -> State<&'_ Q> { - self.state() + self.head.state.to_ref() } - fn symbol(&self) -> &S { - &self.symbol + fn current_symbol(&self) -> &S { + self.symbol() } } -impl Directive for crate::Tail { +impl Directive for (Direction, State, S) { fn direction(&self) -> Direction { - self.direction + self.0 } fn next_state(&self) -> State<&'_ Q> { - self.state() + self.1.to_ref() } - fn value(&self) -> &S { - self.symbol() + fn next_symbol(&self) -> &S { + &self.2 } } -impl Scope for (State, S) { - fn current_state(&self) -> State<&'_ Q> { - self.0.to_ref() +impl Directive for crate::Tail { + fn direction(&self) -> Direction { + self.direction } - fn symbol(&self) -> &S { - &self.1 + fn next_state(&self) -> State<&'_ Q> { + self.state() + } + + fn next_symbol(&self) -> &S { + self.symbol() } } -impl Directive for (Direction, State, S) { +impl Directive for Rule { fn direction(&self) -> Direction { - self.0 + self.direction() } fn next_state(&self) -> State<&'_ Q> { - self.1.to_ref() + self.tail().state() } - fn value(&self) -> &S { - &self.2 + fn next_symbol(&self) -> &S { + self.write_symbol() } } diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index ab41386..798e2b2 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -7,16 +7,16 @@ use super::Rule; use crate::{Head, State, Tail}; use alloc::vec::{self, Vec}; -type Rules = Vec>; +type RuleVec = Vec>; #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Program { +pub struct Ruleset { pub(crate) initial_state: Option>, - pub(crate) rules: Rules, + pub(crate) rules: RuleVec, } -impl Program { +impl Ruleset { pub fn new() -> Self { Self { initial_state: None, @@ -62,11 +62,11 @@ impl Program { self.initial_state.as_ref().map(|state| state.to_ref()) } /// Returns a reference to the instructions. - pub const fn instructions(&self) -> &Rules { + pub const fn instructions(&self) -> &RuleVec { &self.rules } /// Returns a mutable reference to the instructions. - pub fn instructions_mut(&mut self) -> &mut Rules { + pub fn instructions_mut(&mut self) -> &mut RuleVec { &mut self.rules } /// Returns an iterator over the elements. @@ -143,19 +143,19 @@ impl Program { } } -impl AsRef<[Rule]> for Program { +impl AsRef<[Rule]> for Ruleset { fn as_ref(&self) -> &[Rule] { &self.rules } } -impl AsMut<[Rule]> for Program { +impl AsMut<[Rule]> for Ruleset { fn as_mut(&mut self) -> &mut [Rule] { &mut self.rules } } -impl core::ops::Deref for Program { +impl core::ops::Deref for Ruleset { type Target = [Rule]; fn deref(&self) -> &Self::Target { @@ -163,13 +163,13 @@ impl core::ops::Deref for Program { } } -impl core::ops::DerefMut for Program { +impl core::ops::DerefMut for Ruleset { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.rules } } -impl core::ops::Index> for Program +impl core::ops::Index> for Ruleset where Q: PartialEq, S: PartialEq, @@ -181,8 +181,8 @@ where } } -impl From> for Program { - fn from(instructions: Rules) -> Self { +impl From>> for Ruleset { + fn from(instructions: Vec>) -> Self { Self { initial_state: Some(State::default()), rules: instructions, @@ -190,25 +190,25 @@ impl From> for Program { } } -impl Extend> for Program { +impl Extend> for Ruleset { fn extend>>(&mut self, iter: I) { self.rules.extend(iter) } } -impl FromIterator> for Program +impl FromIterator> for Ruleset where Q: Default, { fn from_iter>>(iter: I) -> Self { Self { initial_state: Some(State::default()), - rules: Rules::from_iter(iter), + rules: RuleVec::from_iter(iter), } } } -impl IntoIterator for Program { +impl IntoIterator for Ruleset { type Item = Rule; type IntoIter = vec::IntoIter; diff --git a/core/src/rules/ruleset.rs b/core/src/rules/ruleset.rs index fb85747..0a2bcf7 100644 --- a/core/src/rules/ruleset.rs +++ b/core/src/rules/ruleset.rs @@ -9,12 +9,12 @@ use std::collections::hash_map::{self, HashMap}; #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize))] -pub struct RuleSet { +pub struct RuleMap { pub(crate) initial_state: Option>, pub(crate) rules: HashMap, Tail>, } -impl RuleSet { +impl RuleMap { pub fn new() -> Self { Self { initial_state: None, @@ -199,7 +199,7 @@ impl RuleSet { } #[cfg(feature = "serde")] -impl<'a, Q, S> serde::Deserialize<'a> for RuleSet +impl<'a, Q, S> serde::Deserialize<'a> for RuleMap where Q: Eq + core::hash::Hash + serde::Deserialize<'a>, S: Eq + core::hash::Hash + serde::Deserialize<'a>, @@ -217,7 +217,7 @@ where Q: Eq + core::hash::Hash + serde::Deserialize<'a>, S: Eq + core::hash::Hash + serde::Deserialize<'a>, { - type Value = RuleSet; + type Value = RuleMap; fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { formatter.write_str("a map of rules") @@ -231,7 +231,7 @@ where while let Some((head, tail)) = map.next_entry()? { rules.insert(head, tail); } - Ok(RuleSet { + Ok(RuleMap { initial_state: None, rules, }) @@ -244,7 +244,7 @@ where } } -impl core::iter::Extend<(Head, Tail)> for RuleSet +impl core::iter::Extend<(Head, Tail)> for RuleMap where Q: Eq + core::hash::Hash, S: Eq + core::hash::Hash, @@ -259,7 +259,7 @@ where } } -impl core::iter::Extend> for RuleSet +impl core::iter::Extend> for RuleMap where Q: Eq + core::hash::Hash, S: Eq + core::hash::Hash, @@ -274,7 +274,7 @@ where } } -impl core::ops::Index> for RuleSet +impl core::ops::Index> for RuleMap where Q: Eq + core::hash::Hash, S: Eq + core::hash::Hash, @@ -286,7 +286,7 @@ where } } -impl core::iter::FromIterator<(Head, Tail)> for RuleSet +impl core::iter::FromIterator<(Head, Tail)> for RuleMap where Q: Default + Eq + core::hash::Hash, S: Eq + core::hash::Hash, @@ -299,7 +299,7 @@ where } } -impl core::iter::FromIterator> for RuleSet +impl core::iter::FromIterator> for RuleMap where Q: Default + Eq + core::hash::Hash, S: Eq + core::hash::Hash, @@ -312,7 +312,7 @@ where } } -impl core::iter::IntoIterator for RuleSet +impl core::iter::IntoIterator for RuleMap where Q: Eq + core::hash::Hash, S: Eq + core::hash::Hash, @@ -325,7 +325,7 @@ where } } -impl<'a, Q, S> core::iter::IntoIterator for &'a RuleSet +impl<'a, Q, S> core::iter::IntoIterator for &'a RuleMap where Q: Eq + core::hash::Hash, S: Eq + core::hash::Hash, @@ -338,7 +338,7 @@ where } } -impl<'a, Q, S> core::iter::IntoIterator for &'a mut RuleSet +impl<'a, Q, S> core::iter::IntoIterator for &'a mut RuleMap where Q: Eq + core::hash::Hash, S: Eq + core::hash::Hash, diff --git a/core/src/state/impls/impl_repr.rs b/core/src/state/impls/impl_repr.rs index ec9270e..adb332c 100644 --- a/core/src/state/impls/impl_repr.rs +++ b/core/src/state/impls/impl_repr.rs @@ -80,6 +80,24 @@ impl State<()> { } } +impl State { + pub fn from_true() -> Self { + Self(true) + } + + pub fn from_false() -> Self { + Self(false) + } + + pub fn is_true(&self) -> bool { + self.get() + } + + pub fn is_false(&self) -> bool { + !self.get() + } +} + impl State> { /// Attempts to downcast the state to a concrete type `Q`; returns an error if the state /// is not of type `Q`. diff --git a/core/src/tape/hash_tape.rs b/core/src/tape/hash_tape.rs index ec051dc..d0d6658 100644 --- a/core/src/tape/hash_tape.rs +++ b/core/src/tape/hash_tape.rs @@ -10,7 +10,7 @@ pub(crate) type Hdx = isize; #[derive(Clone, Debug, Default)] pub struct HashTape { - cursor: Hdx, + index: Hdx, store: HashMap, ticks: usize, } @@ -18,7 +18,7 @@ pub struct HashTape { impl HashTape { pub fn new() -> HashTape { HashTape { - cursor: 0, + index: 0, store: HashMap::new(), ticks: 0, } @@ -26,7 +26,7 @@ impl HashTape { pub fn from_data(data: HashMap) -> HashTape { HashTape { - cursor: 0, + index: 0, store: data, ticks: 0, } @@ -37,7 +37,7 @@ impl HashTape { I: IntoIterator, { HashTape { - cursor: 0, + index: 0, store: HashMap::from_iter(iter), ticks: 0, } @@ -51,8 +51,8 @@ impl HashTape { Self::from_iter(iter) } /// Returns the current position of the head. - pub fn cursor(&self) -> Hdx { - self.cursor + pub fn current_position(&self) -> Hdx { + self.index } /// Returns the total number of steps taken by the head. pub fn ticks(&self) -> usize { @@ -60,13 +60,13 @@ impl HashTape { } /// clears the tape. pub fn clear(&mut self) { - self.cursor = 0; + self.index = 0; self.store.clear(); self.ticks = 0; } /// Returns the entry in the tape at the current index. pub fn current_entry(&mut self) -> hash_map::Entry { - self.store.entry(self.cursor) + self.store.entry(self.index) } /// Returns a mutable entry in the tape at the given index. pub fn entry(&mut self, index: Hdx) -> hash_map::Entry { @@ -119,7 +119,7 @@ impl HashTape { /// Returns a mutable reference to the value of the head at the current position; on empty, /// the given value is inserted and returned. pub fn or_insert(&mut self, default: V) -> &mut V { - self.store.entry(self.cursor).or_insert(default) + self.store.entry(self.index).or_insert(default) } /// Returns a mutable reference to the value of the head at the current position; on empty, /// the function is evaluated and the result is inserted and returned. @@ -127,7 +127,7 @@ impl HashTape { where F: FnOnce() -> V, { - self.store.entry(self.cursor).or_insert_with(default) + self.store.entry(self.index).or_insert_with(default) } /// Returns a mutable reference to the value of the head at the current position; if the /// value is not present, the default value is inserted and returned. @@ -135,7 +135,7 @@ impl HashTape { where V: Default, { - self.store.entry(self.cursor).or_default() + self.store.entry(self.index).or_default() } /// Removes the value at the given index. pub fn remove(&mut self, index: Hdx) -> Option { @@ -148,13 +148,13 @@ impl HashTape { /// Shifts the cursor in the given direction. pub fn shift(&mut self, direction: Direction) { - self.cursor += direction; + self.index += direction; self.ticks += 1; } /// Returns a reference to the value at the current cursor position. pub fn read(&self) -> Option<&V> { - self.store.get(&self.cursor) + self.store.get(&self.index) } pub fn read_mut(&mut self) -> &mut V @@ -165,7 +165,7 @@ impl HashTape { } pub fn write(&mut self, step: Direction, value: V) { - let _ = self.store.insert(self.cursor, value); + let _ = self.store.insert(self.index, value); self.shift(step); } } diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index a40f737..e8d4bfc 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -11,7 +11,6 @@ pub use self::tape::StdTape; pub(crate) mod tape; -#[cfg(feature = "std")] pub mod hash_tape; pub(crate) mod prelude { @@ -21,27 +20,28 @@ pub(crate) mod prelude { use core::option::Option; #[doc(hidden)] -pub trait Mem { - type Key; - type Value; - - fn clear(&mut self); +pub trait RawIndex { + private!(); +} - fn get(&self, key: &Self::Key) -> Option<&Self::Value>; +pub trait Index: RawIndex { + fn increment(self) -> Self; - fn get_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value>; + fn decrement(self) -> Self; +} - fn insert(&mut self, key: Self::Key, value: Self::Value); +pub trait HashIndex: Index + core::cmp::Eq + core::hash::Hash {} - fn is_empty(&self) -> bool; +#[doc(hidden)] +pub trait RawTape { + type Elem; - fn len(&self) -> usize; + private!(); } #[doc(hidden)] -pub trait Tape { +pub trait Tape: RawTape { type Index; - type Elem; fn clear(&mut self); @@ -65,29 +65,42 @@ use alloc::vec::Vec; use std::collections::HashMap; #[cfg(feature = "alloc")] -impl Mem for Vec { - type Key = usize; - type Value = V; +impl RawTape for Vec { + type Elem = A; + + seal!(); +} + +#[cfg(feature = "std")] +impl RawTape for HashMap { + type Elem = A; + + seal!(); +} + +#[cfg(feature = "alloc")] +impl Tape for Vec { + type Index = usize; fn clear(&mut self) { Vec::clear(self); } - fn get(&self, key: &Self::Key) -> Option<&Self::Value> { + fn get(&self, key: &Self::Index) -> Option<&V> { match key { key if *key < self.len() => Some(&self[*key]), _ => None, } } - fn get_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value> { + fn get_mut(&mut self, key: &Self::Index) -> Option<&mut V> { match key { key if *key < self.len() => Some(&mut self[*key]), _ => None, } } - fn insert(&mut self, key: Self::Key, value: Self::Value) { + fn insert(&mut self, key: Self::Index, value: V) { Vec::insert(self, key, value); } @@ -101,27 +114,26 @@ impl Mem for Vec { } #[cfg(feature = "std")] -impl Mem for HashMap +impl Tape for HashMap where K: Eq + std::hash::Hash, V: Eq + std::hash::Hash, { - type Key = K; - type Value = V; + type Index = K; fn clear(&mut self) { HashMap::clear(self); } - fn get(&self, key: &Self::Key) -> Option<&Self::Value> { + fn get(&self, key: &K) -> Option<&V> { HashMap::get(self, key) } - fn get_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value> { + fn get_mut(&mut self, key: &K) -> Option<&mut V> { HashMap::get_mut(self, key) } - fn insert(&mut self, key: Self::Key, value: Self::Value) { + fn insert(&mut self, key: K, value: V) { HashMap::insert(self, key, value); } @@ -133,3 +145,33 @@ where HashMap::len(self) } } + +macro_rules! impl_index { + (@impl $T:ty) => { + impl RawIndex for $T { + seal!(); + } + }; + ($($T:ty),* $(,)?) => { + $( + impl_index!(@impl $T); + )* + }; +} + +impl_index!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize); + +impl Index for T +where + T: RawIndex + core::ops::Add + core::ops::Sub + num::One, +{ + fn increment(self) -> Self { + self + T::one() + } + + fn decrement(self) -> Self { + self - T::one() + } +} + +impl HashIndex for T where T: Index + core::cmp::Eq + core::hash::Hash {} diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index dd41cf9..5b2d5f1 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -24,7 +24,7 @@ use alloc::vec::Vec; #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct StdTape { - cursor: usize, + index: usize, store: Vec, ticks: Cell, } @@ -38,7 +38,7 @@ impl Default for StdTape { impl StdTape { pub fn new() -> Self { StdTape { - cursor: 0, + index: 0, store: Vec::::new(), ticks: Cell::default(), } @@ -46,7 +46,7 @@ impl StdTape { /// Constructs a new tape from an iterator. pub fn from_iter(iter: impl IntoIterator) -> Self { StdTape { - cursor: 0, + index: 0, store: Vec::from_iter(iter), ticks: Cell::default(), } @@ -54,7 +54,7 @@ impl StdTape { /// Constructs a new, empty tape with the specified capacity. pub fn with_capacity(capacity: usize) -> Self { StdTape { - cursor: 0, + index: 0, store: Vec::::with_capacity(capacity), ticks: Cell::default(), } @@ -120,21 +120,21 @@ impl StdTape { } /// Returns the current position of the tape head; pub fn position(&self) -> usize { - self.cursor + self.index } /// Attempts to read the symbol at the current position of the tape head. pub fn read(&self) -> Result<&S, Error> { - self.get(self.cursor) - .ok_or(Error::index_out_of_bounds(self.cursor, self.len())) + self.get(self.index) + .ok_or(Error::index_out_of_bounds(self.index, self.len())) } /// Writes the given symbol to the tape at the current position of the tape head. pub fn write(&mut self, symbol: S) { - if self.cursor == usize::MAX { + if self.index == usize::MAX { self.store.insert(0, symbol); - } else if self.cursor == self.store.len() { + } else if self.index == self.store.len() { self.store.push(symbol); } else { - self.store[self.cursor] = symbol; + self.store[self.index] = symbol; } } @@ -149,7 +149,7 @@ impl StdTape { } fn shift(&mut self, direction: Direction) -> usize { - self.cursor = direction.apply_unsigned(self.cursor) % self.store.len(); + self.index = direction.apply_unsigned(self.index) % self.store.len(); self.position() } } @@ -157,7 +157,7 @@ impl StdTape { impl StdTape { pub fn from_str(input: &str) -> StdTape { StdTape { - cursor: 0, + index: 0, store: input.chars().collect(), ticks: Cell::default(), } @@ -209,7 +209,7 @@ where fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { for (i, c) in self.store.iter().enumerate() { match c { - s if i == self.cursor => write!(f, "[{s:?}]")?, + s if i == self.index => write!(f, "[{s:?}]")?, _ => write!(f, "{c:?}")?, } } @@ -224,7 +224,7 @@ where 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}]")?, + b if i == self.index => write!(f, "[{b}]")?, _ => write!(f, "{c}")?, } } diff --git a/core/src/traits/mod.rs b/core/src/traits/mod.rs index 5d9fbec..4c83c99 100644 --- a/core/src/traits/mod.rs +++ b/core/src/traits/mod.rs @@ -11,6 +11,8 @@ pub(crate) mod symbols; #[doc(hidden)] pub mod io; +#[doc(hidden)] +pub mod transform; pub(crate) mod prelude { pub use super::convert::*; diff --git a/core/src/traits/transform.rs b/core/src/traits/transform.rs new file mode 100644 index 0000000..42ddf7a --- /dev/null +++ b/core/src/traits/transform.rs @@ -0,0 +1,58 @@ +/* + Appellation: transform + Contrib: FL03 +*/ +use crate::{Direction, Head, State}; + +/// [Handle] is a generic trait describing objects capable of handling some input and producing +/// some output. +pub trait Handle { + type Output; + + fn handle(&mut self, args: T) -> Self::Output; +} + +/// [TM] +pub trait TM { + type Idx: Copy + core::ops::Add; + + fn process(&mut self, direction: Direction, state: State, symbol: A) -> Head { + let pos = self.position(); + self.write(symbol); + self.scope_mut().replace(state, pos + direction) + } + + fn read(&self) -> Option; + + fn scope(&self) -> &Head; + + fn scope_mut(&mut self) -> &mut Head; + + fn write(&mut self, symbol: A) -> Option; + + fn position(&self) -> Self::Idx { + self.scope().symbol + } +} + +pub trait Driver { + type Head; + + fn read(&self) -> Option; + + fn scope(&self) -> Head<&'_ Q, &'_ A>; + + fn write(&mut self, symbol: A) -> Option; +} + +pub trait Read { + type Output; + + fn read(&self) -> Self::Output; +} + +pub trait Write { + type Output; + + fn write(&self) -> Self::Output; +} diff --git a/core/src/types/cell.rs b/core/src/types/cell.rs index bf0226b..4b3689d 100644 --- a/core/src/types/cell.rs +++ b/core/src/types/cell.rs @@ -2,22 +2,26 @@ Appellation: cell Contrib: FL03 */ -use crate::{Alphabet, Head, State}; +use crate::{Head, State}; +use crate::tape::RawTape; -pub struct Cell -where - S: Alphabet, -{ +pub struct Cell { pub index: isize, - pub state: State<*const Q>, - pub symbol: *const S::Elem, + pub state: State, + pub symbol: A, } -pub struct Snapshot +pub struct Snapshot<'a, Q, M> where - S: Alphabet, + M: RawTape, { pub index: isize, - pub head: Head, - pub tape: S, + pub head: Head<&'a Q, *const M::Elem>, + pub tape: M, +} + +impl Cell { + pub fn new(index: isize, state: State, symbol: A) -> Self { + Self { index, state, symbol } + } } diff --git a/core/src/types/head.rs b/core/src/types/head.rs index 13e93f6..ec94649 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -22,31 +22,22 @@ pub struct Head { } impl Head { - pub fn new(State(state): State, symbol: S) -> Self { - Self { - state: State(state), - symbol, - } + pub fn new(state: State, symbol: S) -> Self { + Self { state, symbol } } /// Create a new instance of the [Head] using the given state and default symbol. - pub fn from_state(State(state): State) -> Self + pub fn from_state(state: State) -> Self where S: Default, { - Self { - state: State(state), - symbol: Default::default(), - } + Self::new(state, S::default()) } /// Create a new instance of the [Head] using the given symbol and default state. pub fn from_symbol(symbol: S) -> Self where Q: Default, { - Self { - state: Default::default(), - symbol, - } + Self::new(State::default(), symbol) } /// Create a new instance from a 2-tuple: ([state](State), symbol) pub fn from_tuple((state, symbol): (State, S)) -> Self { diff --git a/core/src/types/tail.rs b/core/src/types/tail.rs index 3b155da..2716cc9 100644 --- a/core/src/types/tail.rs +++ b/core/src/types/tail.rs @@ -33,9 +33,25 @@ impl Tail { symbol, } } - - pub fn create() -> TailBuilder { - TailBuilder::new(Direction::Right) + /// Returns an instance of [TailBuilder] allowing developers to construct a [Tail] with + /// a fluent API + pub fn init() -> TailBuilder { + TailBuilder::new() + } + /// Configures the tail with a new direction + pub fn with_direction(self, direction: Direction) -> Self { + Self { direction, ..self } + } + /// Configures the tail with a new state + pub fn with_state(self, State(state): State) -> Self { + Self { + state: State(state), + ..self + } + } + /// Configures the tail with a new symbol + pub fn with_symbol(self, symbol: S) -> Self { + Self { symbol, ..self } } /// Returns the direction, state, and symbol as a 3-tuple pub fn as_tuple(&self) -> (Direction, &State, &S) { @@ -204,7 +220,15 @@ mod builder { } impl TailBuilder { - pub fn new(direction: Direction) -> Self { + pub fn new() -> Self { + Self { + direction: Direction::Right, + state: None, + symbol: None, + } + } + + pub fn from_direction(direction: Direction) -> Self { Self { direction, state: None, diff --git a/core/src/types/transition.rs b/core/src/types/transition.rs index 9a3a42e..ac682b3 100644 --- a/core/src/types/transition.rs +++ b/core/src/types/transition.rs @@ -5,6 +5,11 @@ use super::{Direction, Head}; use crate::State; +/// [Transition] is a type representing the tail of a Turing machine; +/// +/// Formally, a tail is defined to be a 3-tuple (direction, state, symbol). Considering the +/// head of a machine is a 2-tuple (state, symbol), the tail simply extends the head with a +/// direction. #[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr( feature = "serde", diff --git a/core/tests/actor.rs b/core/tests/actor.rs index 3380b0f..79047b0 100644 --- a/core/tests/actor.rs +++ b/core/tests/actor.rs @@ -5,7 +5,7 @@ extern crate rstm_core as rstm; use rstm::actors::Actor; -use rstm::rules::{Program, Rule}; +use rstm::rules::{Rule, Ruleset}; use rstm::{ruleset, State}; lazy_static::lazy_static! { @@ -25,7 +25,7 @@ fn busy_beaver() { let initial_state = State(0_isize); let input = [0_usize; 10]; - let program = Program::from_iter(*RULES); + let program = Ruleset::from_iter(*RULES); let actor = Actor::from_state(initial_state).with_alpha(input); let mut rt = actor.execute(program); diff --git a/core/tests/rules.rs b/core/tests/rules.rs index bed4207..4fa7fe6 100644 --- a/core/tests/rules.rs +++ b/core/tests/rules.rs @@ -4,7 +4,7 @@ */ extern crate rstm_core as rstm; -use rstm::rules::Program; +use rstm::rules::Ruleset; use rstm::{ruleset, Direction, Head, State, Tail}; #[test] @@ -20,7 +20,7 @@ fn ruleset() { // validate the number of rules within the ruleset assert_eq!(rules.len(), 6); // create a new program using the ruleset - let program = Program::from_iter(rules); + let program = Ruleset::from_iter(rules); // validate the number of rules within the program assert_eq!(rules.len(), program.len()); // create a new head for a rule within the program diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index 02af905..4de5724 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -25,6 +25,7 @@ full = [ # ********* [FF] Dependencies ********* alloc = [ + "rstm-core/alloc", "serde?/alloc", ] @@ -39,11 +40,12 @@ tracing = [ ] # ********* [FF] Environments ********* -# std = [ -# "alloc", -# "serde?/std", -# "strum/std", -# ] +std = [ + "alloc", + "rstm-core/std", + "serde?/std", + "strum/std", +] [lib] bench = true @@ -60,17 +62,18 @@ required-features = ["alloc", "tracing"] thiserror.workspace = true [dependencies.rstm-core] +default-features = false path = "../core" version = "0.0.4" [dependencies.serde] -# default-features = false +default-features = false features = ["derive"] optional = true version = "1" [dependencies.strum] -# default-features = false +default-features = false features = ["derive"] version = "0.26" diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index 4584ba7..7acfc33 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -4,7 +4,7 @@ */ extern crate rstm; -use rstm::{ruleset, Actor, Program, State}; +use rstm::{ruleset, Actor, Ruleset, State}; fn main() -> Result<(), Box> { _tracing("debug"); @@ -22,7 +22,7 @@ fn main() -> Result<(), Box> { (-1, 1) -> Left(1, 1), ]; // create a new program from the ruleset - let program = Program::from_iter(rules); + let program = Ruleset::from_iter(rules); // create a new instance of the machine let tm = dbg!(Actor::new(alpha, initial_state, 0)); tm.execute(program).run()?; diff --git a/rstm/src/models/base.rs b/rstm/src/models/base.rs index 2a4d0de..2de841a 100644 --- a/rstm/src/models/base.rs +++ b/rstm/src/models/base.rs @@ -2,7 +2,7 @@ Appellation: tm Contrib: FL03 */ -use crate::rules::Program; +use crate::rules::Ruleset; use crate::state::{halt::HaltState, State}; use crate::{Error, Head, StdTape, Symbolic, Tail}; @@ -14,13 +14,13 @@ use crate::{Error, Head, StdTape, Symbolic, Tail}; #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct StdTM { - pub(crate) program: Program, + pub(crate) program: Ruleset, pub(crate) state: HaltState, pub(crate) tape: StdTape, } impl StdTM { - pub fn new(program: Program, tape: StdTape) -> Self + pub fn new(program: Ruleset, tape: StdTape) -> Self where Q: Clone + Default, S: Default, @@ -36,7 +36,7 @@ impl StdTM { } } /// Returns an immutable reference to the [program](Program) - pub const fn program(&self) -> &Program { + pub const fn program(&self) -> &Ruleset { &self.program } /// Creates a new instance of a [head](Head) from references to the current state and symbol; diff --git a/core/src/actors/engine.rs b/rstm/src/models/engine.rs similarity index 78% rename from core/src/actors/engine.rs rename to rstm/src/models/engine.rs index 0d8ab36..cb76610 100644 --- a/core/src/actors/engine.rs +++ b/rstm/src/models/engine.rs @@ -3,34 +3,35 @@ Contrib: FL03 */ #![cfg(feature = "std")] +use crate::rules::Rule; use crate::state::RawState; -use crate::{Direction, Error, Head, Program, State}; +use crate::{Direction, Error, Head, Ruleset, State}; use std::collections::hash_map::{self, HashMap}; -pub struct Engine +pub struct TMH where Q: RawState, { - pub(crate) program: Program, + pub(crate) program: Ruleset, pub(crate) scope: Head, // Head, pub(crate) tape: HashMap, } -impl Engine +impl TMH where Q: RawState, { - // pub fn new(initial_state: State) -> Self { - // Self { - // program: Program::new().initial_state(state), - // scope: Head { - // state: initial_state, - // symbol: 0, - // }, - // tape: HashMap::new(), - // } - // } + pub fn new(initial_state: State) -> Self { + Self { + program: Ruleset::new(), + scope: Head { + state: initial_state, + symbol: 0, + }, + tape: HashMap::new(), + } + } pub fn with_input(self, input: I) -> Self where I: IntoIterator, @@ -40,10 +41,17 @@ where ..self } } - pub fn with_program(self, program: Program) -> Self { + pub fn with_program(self, program: Ruleset) -> Self { Self { program, ..self } } + pub fn load(&mut self, rules: I) + where + I: IntoIterator>, + { + self.program.extend(rules); + } + pub fn current_state(&self) -> State<&'_ Q> { self.scope.state() } diff --git a/rstm/src/models/mod.rs b/rstm/src/models/mod.rs index 90027e3..c391e1f 100644 --- a/rstm/src/models/mod.rs +++ b/rstm/src/models/mod.rs @@ -6,6 +6,7 @@ pub use self::base::StdTM; pub mod base; +pub mod engine; pub(crate) mod prelude { pub use super::base::StdTM; From 43c7947b146929d5efa84e3b18d9531e4c35da23 Mon Sep 17 00:00:00 2001 From: FL03 Date: Sat, 7 Sep 2024 09:41:32 -0500 Subject: [PATCH 24/27] update Signed-off-by: FL03 --- core/src/lib.rs | 17 +-- core/src/mem/mod.rs | 16 ++ core/src/mem/store.rs | 209 +++++++++++++++++++++++++++ core/src/{ => mem}/tape/hash_tape.rs | 2 +- core/src/{ => mem}/tape/mod.rs | 45 +----- core/src/{ => mem}/tape/tape.rs | 0 core/src/traits/container.rs | 32 ++++ core/src/traits/indexing.rs | 50 +++++++ core/src/traits/mod.rs | 12 +- core/src/types/cell.rs | 23 ++- core/src/types/direction.rs | 16 +- core/src/types/head.rs | 2 +- core/src/types/mod.rs | 2 + core/src/types/snapshot.rs | 25 ++++ core/src/types/tail.rs | 2 +- core/tests/tape.rs | 2 +- rstm/Cargo.toml | 2 +- rstm/src/models/base.rs | 2 +- 18 files changed, 375 insertions(+), 84 deletions(-) create mode 100644 core/src/mem/mod.rs create mode 100644 core/src/mem/store.rs rename core/src/{ => mem}/tape/hash_tape.rs (99%) rename core/src/{ => mem}/tape/mod.rs (75%) rename core/src/{ => mem}/tape/tape.rs (100%) create mode 100644 core/src/traits/container.rs create mode 100644 core/src/traits/indexing.rs create mode 100644 core/src/types/snapshot.rs diff --git a/core/src/lib.rs b/core/src/lib.rs index f78bc19..7a6662a 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -28,7 +28,6 @@ pub use self::{ error::Error, rules::{Rule, Ruleset}, state::State, - tape::StdTape, traits::prelude::*, types::prelude::*, }; @@ -48,18 +47,18 @@ pub(crate) mod seal; pub mod actors; pub mod error; +pub mod mem; pub mod rules; pub mod state; -pub mod tape; pub mod traits; pub mod types; pub mod prelude { - pub use crate::actors::prelude::*; - pub use crate::error::Error; - 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::*; + pub use super::actors::prelude::*; + pub use super::error::Error; + pub use super::mem::prelude::*; + pub use super::rules::prelude::*; + pub use super::state::prelude::*; + pub use super::traits::prelude::*; + pub use super::types::prelude::*; } diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs new file mode 100644 index 0000000..74573bd --- /dev/null +++ b/core/src/mem/mod.rs @@ -0,0 +1,16 @@ +/* + Appellation: mem + Contrib: FL03 +*/ +//! # Memory (mem) +//! +//! +#[doc(inline)] +pub use self::store::*; + +pub mod store; +pub mod tape; + +pub(crate) mod prelude { + pub use super::tape::prelude::*; +} diff --git a/core/src/mem/store.rs b/core/src/mem/store.rs new file mode 100644 index 0000000..da988b2 --- /dev/null +++ b/core/src/mem/store.rs @@ -0,0 +1,209 @@ +/* + Appellation: store + Contrib: FL03 +*/ + +/// [RawMemory] is a trait that provides a common interface for memory storage. +pub trait RawMemory { + type Elem; + + private!(); + + fn is_empty(&self) -> bool { + self.len() == 0 + } + + fn len(&self) -> usize; + + fn to_vec(&self) -> Vec + where + Self::Elem: Clone; +} + +/// [Sequential] extends the base trait [RawMemory] to provide sequential access to memory. +pub trait Sequential: RawMemory { + fn as_ptr(&self) -> *const Self::Elem; + + fn as_mut_ptr(&mut self) -> *mut Self::Elem; + + fn as_slice(&self) -> &[Self::Elem]; + + fn as_mut_slice(&mut self) -> &mut [Self::Elem]; +} + +pub trait Memory: RawMemory { + type Key; + + fn get(&self, index: &Self::Key) -> Option<&Self::Elem>; + + fn get_mut(&mut self, index: &Self::Key) -> Option<&mut Self::Elem>; +} + +pub trait MemoryMut: Memory { + fn clear(&mut self); + + fn insert(&mut self, index: usize, elem: Self::Elem); + + fn remove(&mut self, index: usize) -> Option; +} + +/* + ************* Implementations ************* +*/ +impl RawMemory for [T] { + type Elem = T; + + seal!(); + + fn is_empty(&self) -> bool { + <[T]>::is_empty(self) + } + + fn len(&self) -> usize { + <[T]>::len(self) + } + + fn to_vec(&self) -> Vec + where + T: Clone, + { + <[T]>::to_vec(self) + } +} + +impl Memory for [T] { + type Key = usize; + + fn get(&self, index: &usize) -> Option<&T> { + <[T]>::get(self, *index) + } + + fn get_mut(&mut self, index: &usize) -> Option<&mut T> { + <[T]>::get_mut(self, *index) + } +} + +impl Sequential for [T] { + fn as_ptr(&self) -> *const T { + <[T]>::as_ptr(self) + } + + fn as_mut_ptr(&mut self) -> *mut T { + <[T]>::as_mut_ptr(self) + } + + fn as_slice(&self) -> &[T] { + &self + } + + fn as_mut_slice(&mut self) -> &mut [T] { + self + } +} + +#[cfg(feature = "alloc")] +mod impl_alloc { + use super::{Memory, RawMemory, Sequential}; + use alloc::vec::Vec; + + impl RawMemory for Vec { + type Elem = T; + + seal!(); + + fn is_empty(&self) -> bool { + Vec::is_empty(self) + } + + fn len(&self) -> usize { + Vec::len(self) + } + + fn to_vec(&self) -> Vec + where + T: Clone, + { + self.clone() + } + } + + impl Memory for Vec { + type Key = usize; + + fn get(&self, index: &usize) -> Option<&T> { + if *index < self.len() { + Some(&self[*index]) + } else { + None + } + } + + fn get_mut(&mut self, index: &usize) -> Option<&mut T> { + if *index < self.len() { + Some(&mut self[*index]) + } else { + None + } + } + } + + impl Sequential for Vec { + fn as_ptr(&self) -> *const T { + Vec::as_ptr(self) + } + + fn as_mut_ptr(&mut self) -> *mut T { + Vec::as_mut_ptr(self) + } + + fn as_slice(&self) -> &[T] { + Vec::as_slice(self) + } + + fn as_mut_slice(&mut self) -> &mut [T] { + Vec::as_mut_slice(self) + } + } +} + +#[cfg(feature = "std")] +mod impl_std { + use super::{Memory, RawMemory}; + use std::collections::HashMap; + + impl RawMemory for HashMap { + type Elem = V; + + seal!(); + + fn is_empty(&self) -> bool { + HashMap::is_empty(self) + } + + fn len(&self) -> usize { + HashMap::len(self) + } + + fn to_vec(&self) -> Vec + where + V: Clone, + { + self.values().cloned().collect() + } + } + + impl Memory for HashMap + where + K: Eq + core::hash::Hash, + { + type Key = K; + + fn get(&self, index: &K) -> Option<&V> { + HashMap::get(self, index) + } + + fn get_mut(&mut self, index: &K) -> Option<&mut V> { + HashMap::get_mut(self, index) + } + } +} diff --git a/core/src/tape/hash_tape.rs b/core/src/mem/tape/hash_tape.rs similarity index 99% rename from core/src/tape/hash_tape.rs rename to core/src/mem/tape/hash_tape.rs index d0d6658..928e773 100644 --- a/core/src/tape/hash_tape.rs +++ b/core/src/mem/tape/hash_tape.rs @@ -2,7 +2,7 @@ Appellation: hash_tape Contrib: FL03 */ -#![cfg(feature = "std")] + use crate::Direction; use std::collections::hash_map::{self, HashMap}; diff --git a/core/src/tape/mod.rs b/core/src/mem/tape/mod.rs similarity index 75% rename from core/src/tape/mod.rs rename to core/src/mem/tape/mod.rs index e8d4bfc..ba76b51 100644 --- a/core/src/tape/mod.rs +++ b/core/src/mem/tape/mod.rs @@ -7,10 +7,12 @@ //! 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. +#[doc(inline)] pub use self::tape::StdTape; pub(crate) mod tape; +#[cfg(feature = "std")] pub mod hash_tape; pub(crate) mod prelude { @@ -19,19 +21,6 @@ pub(crate) mod prelude { use core::option::Option; -#[doc(hidden)] -pub trait RawIndex { - private!(); -} - -pub trait Index: RawIndex { - fn increment(self) -> Self; - - fn decrement(self) -> Self; -} - -pub trait HashIndex: Index + core::cmp::Eq + core::hash::Hash {} - #[doc(hidden)] pub trait RawTape { type Elem; @@ -145,33 +134,3 @@ where HashMap::len(self) } } - -macro_rules! impl_index { - (@impl $T:ty) => { - impl RawIndex for $T { - seal!(); - } - }; - ($($T:ty),* $(,)?) => { - $( - impl_index!(@impl $T); - )* - }; -} - -impl_index!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize); - -impl Index for T -where - T: RawIndex + core::ops::Add + core::ops::Sub + num::One, -{ - fn increment(self) -> Self { - self + T::one() - } - - fn decrement(self) -> Self { - self - T::one() - } -} - -impl HashIndex for T where T: Index + core::cmp::Eq + core::hash::Hash {} diff --git a/core/src/tape/tape.rs b/core/src/mem/tape/tape.rs similarity index 100% rename from core/src/tape/tape.rs rename to core/src/mem/tape/tape.rs diff --git a/core/src/traits/container.rs b/core/src/traits/container.rs new file mode 100644 index 0000000..cc36f36 --- /dev/null +++ b/core/src/traits/container.rs @@ -0,0 +1,32 @@ +/* + Appellation: container + Contrib: FL03 +*/ + +pub trait RawContainer { + type Elem; +} + +/* + ************* Implementations ************* +*/ + +impl RawContainer for Vec { + type Elem = T; +} + +impl RawContainer for Box<[T]> { + type Elem = T; +} + +impl RawContainer for [T] { + type Elem = T; +} + +impl RawContainer for &mut [T] { + type Elem = T; +} + +impl RawContainer for &mut [T; N] { + type Elem = T; +} diff --git a/core/src/traits/indexing.rs b/core/src/traits/indexing.rs new file mode 100644 index 0000000..78b604a --- /dev/null +++ b/core/src/traits/indexing.rs @@ -0,0 +1,50 @@ +/* + Appellation: indexing + Contrib: FL03 +*/ + +#[doc(hidden)] +pub trait RawIndex { + private!(); +} + +pub trait Index: RawIndex { + fn increment(self) -> Self; + + fn decrement(self) -> Self; +} + +pub trait HashIndex: Index + core::cmp::Eq + core::hash::Hash {} + +/* + ************* Implementations ************* +*/ +impl Index for T +where + T: RawIndex + core::ops::Add + core::ops::Sub + num::One, +{ + fn increment(self) -> Self { + self + T::one() + } + + fn decrement(self) -> Self { + self - T::one() + } +} + +impl HashIndex for T where T: Index + core::cmp::Eq + core::hash::Hash {} + +macro_rules! impl_index { + (@impl $T:ty) => { + impl RawIndex for $T { + seal!(); + } + }; + ($($T:ty),* $(,)?) => { + $( + impl_index!(@impl $T); + )* + }; +} + +impl_index!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize); diff --git a/core/src/traits/mod.rs b/core/src/traits/mod.rs index 4c83c99..568c721 100644 --- a/core/src/traits/mod.rs +++ b/core/src/traits/mod.rs @@ -3,12 +3,15 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{convert::*, increment::*, symbols::*}; +pub use self::{convert::*, increment::*, indexing::*, symbols::*}; -pub(crate) mod convert; -pub(crate) mod increment; -pub(crate) mod symbols; +mod convert; +mod increment; +mod indexing; +mod symbols; +#[doc(hidden)] +pub mod container; #[doc(hidden)] pub mod io; #[doc(hidden)] @@ -17,5 +20,6 @@ pub mod transform; pub(crate) mod prelude { pub use super::convert::*; pub use super::increment::*; + pub use super::indexing::*; pub use super::symbols::*; } diff --git a/core/src/types/cell.rs b/core/src/types/cell.rs index 4b3689d..66a225f 100644 --- a/core/src/types/cell.rs +++ b/core/src/types/cell.rs @@ -2,26 +2,21 @@ Appellation: cell Contrib: FL03 */ -use crate::{Head, State}; -use crate::tape::RawTape; +use crate::State; +/// [Cell] is a struct pub struct Cell { - pub index: isize, + pub index: usize, pub state: State, pub symbol: A, } -pub struct Snapshot<'a, Q, M> -where - M: RawTape, -{ - pub index: isize, - pub head: Head<&'a Q, *const M::Elem>, - pub tape: M, -} - impl Cell { - pub fn new(index: isize, state: State, symbol: A) -> Self { - Self { index, state, symbol } + pub fn state(&self) -> State<&Q> { + self.state.to_ref() + } + + pub fn symbol(&self) -> &A { + &self.symbol } } diff --git a/core/src/types/direction.rs b/core/src/types/direction.rs index 55150c2..029de44 100644 --- a/core/src/types/direction.rs +++ b/core/src/types/direction.rs @@ -160,7 +160,7 @@ where } macro_rules! impl_apply_direction { - (@impl unsigned: $T:ty) => { + (@unsigned $T:ty) => { impl core::ops::Add for $T { type Output = $T; @@ -184,7 +184,7 @@ macro_rules! impl_apply_direction { } }; - (@impl $T:ty) => { + (@signed $T:ty) => { impl core::ops::Add for $T { type Output = $T; @@ -201,19 +201,19 @@ macro_rules! impl_apply_direction { } }; - (unsigned: $($T:ty),* $(,)?) => { + (signed: $($T:ty),* $(,)?) => { $( - impl_apply_direction!(@impl unsigned: $T); + impl_apply_direction!(@signed $T); )* }; - ($($T:ty),* $(,)?) => { + (unsigned: $($T:ty),* $(,)?) => { $( - impl_apply_direction!(@impl $T); + impl_apply_direction!(@unsigned $T); )* }; -} -impl_apply_direction!(i8, i16, i32, i64, i128, isize,); +} +impl_apply_direction!(signed: i8, i16, i32, i64, i128, isize,); impl_apply_direction!(unsigned: u8, u16, u32, u64, u128, usize); mod impl_from { diff --git a/core/src/types/head.rs b/core/src/types/head.rs index ec94649..a50a6a2 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -14,7 +14,7 @@ use crate::state::State; derive(serde::Deserialize, serde::Serialize), serde(rename_all = "lowercase") )] -pub struct Head { +pub struct Head { #[cfg_attr(feature = "serde", serde(alias = "current_state"))] pub state: State, #[cfg_attr(feature = "serde", serde(alias = "current_symbol"))] diff --git a/core/src/types/mod.rs b/core/src/types/mod.rs index 354b39c..af66877 100644 --- a/core/src/types/mod.rs +++ b/core/src/types/mod.rs @@ -12,6 +12,8 @@ pub(crate) mod tail; #[doc(hidden)] pub mod cell; #[doc(hidden)] +pub mod snapshot; +#[doc(hidden)] pub mod transition; pub(crate) mod prelude { diff --git a/core/src/types/snapshot.rs b/core/src/types/snapshot.rs new file mode 100644 index 0000000..4e5fb90 --- /dev/null +++ b/core/src/types/snapshot.rs @@ -0,0 +1,25 @@ +/* + Appellation: snapshot + Contrib: FL03 +*/ +use crate::mem::RawMemory; +use crate::State; + +pub struct Snapshot<'a, Q, M> +where + M: RawMemory, +{ + pub state: State<&'a Q>, + pub symbol: *mut M::Elem, + pub tape: M, +} + +impl<'a, Q, A, M> Snapshot<'a, Q, M> +where + A: 'a, + M: RawMemory, +{ + pub fn state(&self) -> State<&'a Q> { + self.state + } +} diff --git a/core/src/types/tail.rs b/core/src/types/tail.rs index 2716cc9..89090d4 100644 --- a/core/src/types/tail.rs +++ b/core/src/types/tail.rs @@ -14,7 +14,7 @@ use crate::{Direction, Head, State}; derive(serde::Deserialize, serde::Serialize), serde(rename_all = "lowercase") )] -pub struct Tail { +pub struct Tail { pub direction: Direction, #[cfg_attr(feature = "serde", serde(alias = "next_state"))] pub state: State, diff --git a/core/tests/tape.rs b/core/tests/tape.rs index 0af6041..c15293a 100644 --- a/core/tests/tape.rs +++ b/core/tests/tape.rs @@ -4,7 +4,7 @@ */ extern crate rstm_core as rstm; -use rstm::tape::StdTape; +use rstm::mem::tape::StdTape; #[test] fn stdtape() { diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index 4de5724..07be993 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -14,7 +14,7 @@ version.workspace = true [features] default = [ - "alloc", + "std", ] full = [ diff --git a/rstm/src/models/base.rs b/rstm/src/models/base.rs index 2de841a..5f92b3a 100644 --- a/rstm/src/models/base.rs +++ b/rstm/src/models/base.rs @@ -2,9 +2,9 @@ Appellation: tm Contrib: FL03 */ +use crate::prelude::{Error, Head, StdTape, Symbolic, Tail}; use crate::rules::Ruleset; use crate::state::{halt::HaltState, State}; -use crate::{Error, Head, StdTape, Symbolic, Tail}; /// # Turing Machine ([StdTm]) /// From 800dfd0ae69bad8f85f35d154741f7beab2bd0d6 Mon Sep 17 00:00:00 2001 From: FL03 Date: Sat, 7 Sep 2024 10:20:30 -0500 Subject: [PATCH 25/27] update Signed-off-by: FL03 --- core/src/actors/exec.rs | 2 + core/src/mem/store.rs | 150 +++++++++++++++++++++------------------- core/src/types/head.rs | 12 ++-- 3 files changed, 85 insertions(+), 79 deletions(-) diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 5f7cc15..9028a1b 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -7,7 +7,9 @@ use crate::{Error, Head, Ruleset, State, Symbolic}; /// pub struct Executor { + /// the actor that will be executing the program pub(crate) actor: Actor, + /// the program being executed pub(crate) program: Ruleset, /// the number of steps taken by the actor pub(crate) steps: usize, diff --git a/core/src/mem/store.rs b/core/src/mem/store.rs index da988b2..8317c93 100644 --- a/core/src/mem/store.rs +++ b/core/src/mem/store.rs @@ -14,14 +14,24 @@ pub trait RawMemory { } fn len(&self) -> usize; +} +pub trait Memory: RawMemory { fn to_vec(&self) -> Vec where Self::Elem: Clone; } +pub trait MemoryMut: Memory { + fn clear(&mut self); + + fn insert(&mut self, index: usize, elem: Self::Elem); + + fn remove(&mut self, index: usize) -> Option; +} + /// [Sequential] extends the base trait [RawMemory] to provide sequential access to memory. -pub trait Sequential: RawMemory { +pub trait SeqMemory: Memory { fn as_ptr(&self) -> *const Self::Elem; fn as_mut_ptr(&mut self) -> *mut Self::Elem; @@ -29,27 +39,44 @@ pub trait Sequential: RawMemory { fn as_slice(&self) -> &[Self::Elem]; fn as_mut_slice(&mut self) -> &mut [Self::Elem]; -} -pub trait Memory: RawMemory { - type Key; - - fn get(&self, index: &Self::Key) -> Option<&Self::Elem>; + fn get(&self, index: I) -> Option<&I::Output> + where + I: core::slice::SliceIndex<[Self::Elem]>; - fn get_mut(&mut self, index: &Self::Key) -> Option<&mut Self::Elem>; + fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where + I: core::slice::SliceIndex<[Self::Elem]>; } -pub trait MemoryMut: Memory { - fn clear(&mut self); +#[doc(hidden)] +pub trait Fetch { + type Output; - fn insert(&mut self, index: usize, elem: Self::Elem); + fn fetch(&self, index: K) -> Option<&Self::Output>; - fn remove(&mut self, index: usize) -> Option; + fn fetch_mut(&mut self, index: K) -> Option<&mut Self::Output>; } /* ************* Implementations ************* */ +impl Fetch for [T] +where + I: core::slice::SliceIndex<[T]>, + I::Output: Sized, +{ + type Output = I::Output; + + fn fetch(&self, index: I) -> Option<&Self::Output> { + <[T]>::get(self, index) + } + + fn fetch_mut(&mut self, index: I) -> Option<&mut Self::Output> { + <[T]>::get_mut(self, index) + } +} + impl RawMemory for [T] { type Elem = T; @@ -62,7 +89,9 @@ impl RawMemory for [T] { fn len(&self) -> usize { <[T]>::len(self) } +} +impl Memory for [T] { fn to_vec(&self) -> Vec where T: Clone, @@ -71,19 +100,7 @@ impl RawMemory for [T] { } } -impl Memory for [T] { - type Key = usize; - - fn get(&self, index: &usize) -> Option<&T> { - <[T]>::get(self, *index) - } - - fn get_mut(&mut self, index: &usize) -> Option<&mut T> { - <[T]>::get_mut(self, *index) - } -} - -impl Sequential for [T] { +impl SeqMemory for [T] { fn as_ptr(&self) -> *const T { <[T]>::as_ptr(self) } @@ -93,20 +110,33 @@ impl Sequential for [T] { } fn as_slice(&self) -> &[T] { - &self + self } fn as_mut_slice(&mut self) -> &mut [T] { self } + + fn get(&self, index: I) -> Option<&I::Output> + where + I: core::slice::SliceIndex<[T]>, + { + <[T]>::get(self, index) + } + + fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where + I: core::slice::SliceIndex<[T]>, + { + <[T]>::get_mut(self, index) + } } #[cfg(feature = "alloc")] mod impl_alloc { - use super::{Memory, RawMemory, Sequential}; use alloc::vec::Vec; - impl RawMemory for Vec { + impl super::RawMemory for Vec { type Elem = T; seal!(); @@ -118,7 +148,9 @@ mod impl_alloc { fn len(&self) -> usize { Vec::len(self) } + } + impl super::Memory for Vec { fn to_vec(&self) -> Vec where T: Clone, @@ -127,27 +159,10 @@ mod impl_alloc { } } - impl Memory for Vec { - type Key = usize; - - fn get(&self, index: &usize) -> Option<&T> { - if *index < self.len() { - Some(&self[*index]) - } else { - None - } - } - - fn get_mut(&mut self, index: &usize) -> Option<&mut T> { - if *index < self.len() { - Some(&mut self[*index]) - } else { - None - } - } - } - - impl Sequential for Vec { + impl super::SeqMemory for Vec + where + Vec: AsRef<[T]>, + { fn as_ptr(&self) -> *const T { Vec::as_ptr(self) } @@ -163,15 +178,28 @@ mod impl_alloc { fn as_mut_slice(&mut self) -> &mut [T] { Vec::as_mut_slice(self) } + + fn get(&self, index: I) -> Option<&I::Output> + where + I: core::slice::SliceIndex<[T]>, + { + <[T]>::get(self, index) + } + + fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where + I: core::slice::SliceIndex<[T]>, + { + <[T]>::get_mut(self, index) + } } } #[cfg(feature = "std")] mod impl_std { - use super::{Memory, RawMemory}; use std::collections::HashMap; - impl RawMemory for HashMap { + impl super::RawMemory for HashMap { type Elem = V; seal!(); @@ -183,27 +211,5 @@ mod impl_std { fn len(&self) -> usize { HashMap::len(self) } - - fn to_vec(&self) -> Vec - where - V: Clone, - { - self.values().cloned().collect() - } - } - - impl Memory for HashMap - where - K: Eq + core::hash::Hash, - { - type Key = K; - - fn get(&self, index: &K) -> Option<&V> { - HashMap::get(self, index) - } - - fn get_mut(&mut self, index: &K) -> Option<&mut V> { - HashMap::get_mut(self, index) - } } } diff --git a/core/src/types/head.rs b/core/src/types/head.rs index a50a6a2..3ffd75e 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -4,10 +4,7 @@ */ use crate::state::State; -/// The [Head] struct represent the state and symbol of an actor at a given moment in time. -/// With respect to a Turing machine, the head defines the current state and symbol of the -/// machine. When associated with a direction the head becomes a tail, instructing the machine -/// to move, write, and transition to a new state. +/// The [Head] is formally defined to be a 2-tuple consisting of a state / symbol pair. #[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr( feature = "serde", @@ -90,18 +87,19 @@ impl Head { pub fn set_symbol(&mut self, symbol: S) { self.symbol = symbol; } - + /// Replaces the current state and symbol with the given state and symbol; returns the + /// previous instance of the head. pub fn replace(&mut self, state: State, symbol: S) -> Self { Head { state: core::mem::replace(&mut self.state, state), symbol: core::mem::replace(&mut self.symbol, symbol), } } - + /// Replaces the current state with the given state, returing the previous state pub fn replace_state(&mut self, state: State) -> State { core::mem::replace(&mut self.state, state) } - + /// Replaces the current symbol with the given symbol, returning the previous symbol pub fn replace_symbol(&mut self, symbol: S) -> S { core::mem::replace(&mut self.symbol, symbol) } From 4b08301566db7bdfea035cf1031725efd4477037 Mon Sep 17 00:00:00 2001 From: FL03 Date: Sat, 7 Sep 2024 10:47:20 -0500 Subject: [PATCH 26/27] update Signed-off-by: FL03 --- clippy.toml | 1 + core/src/actors/exec.rs | 6 +++++- core/src/actors/mod.rs | 30 +++++++++++++++++++++++------- core/src/lib.rs | 1 + core/src/mem/tape/tape.rs | 9 +++++---- core/src/state/state.rs | 2 +- core/src/types/direction.rs | 1 + core/src/types/tail.rs | 6 ++++++ 8 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 clippy.toml diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ + diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 9028a1b..e33571c 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -5,7 +5,11 @@ use super::Actor; use crate::{Error, Head, Ruleset, State, Symbolic}; -/// +/// # [Executor] +/// +/// The [Executor] struct is directly responsible for the execution of a program. From a rustic +/// perspective, the [Executor] is an iterator that reads the current symbol at the head of +/// the tape, pub struct Executor { /// the actor that will be executing the program pub(crate) actor: Actor, diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs index 7f24ae5..d684b58 100644 --- a/core/src/actors/mod.rs +++ b/core/src/actors/mod.rs @@ -17,22 +17,34 @@ pub(crate) mod prelude { pub use super::exec::Executor; } -pub trait Program { - fn get(&self, state: crate::State<&Q>, symbol: &S) -> Option<&crate::Rule>; +use crate::{Direction, Error, Head, Rule, State}; - fn get_mut(&mut self, state: crate::State<&Q>, symbol: &S) -> Option<&mut crate::Rule>; +#[doc(hidden)] +pub trait GetRule { + fn get(&self, state: State<&Q>, symbol: &S) -> Option<&Rule>; + + fn get_mut(&mut self, state: State<&Q>, symbol: &S) -> Option<&mut Rule>; } #[doc(hidden)] -pub trait Runtime { +pub trait Dynamical { + type Output; + + fn step(&mut self, f: F) -> Self::Output; +} + +#[doc(hidden)] +pub trait Engine { fn load(&mut self, program: I) where - I: IntoIterator>; + I: IntoIterator>; + + fn handle(&mut self, direction: Direction, state: State, symbol: S) -> Head; - fn run(&mut self) -> Result<(), crate::Error>; + fn run(&mut self) -> Result<(), Error>; } -impl Runtime for Executor +impl Engine for Executor where Q: Clone + PartialEq + 'static, S: crate::Symbolic, @@ -45,6 +57,10 @@ where self.program.extend(program); } + fn handle(&mut self, direction: Direction, state: State, symbol: S) -> Head { + self.actor.step(direction, state, symbol) + } + fn run(&mut self) -> Result<(), crate::Error> { Executor::run(self) } diff --git a/core/src/lib.rs b/core/src/lib.rs index 7a6662a..9cebb5f 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -19,6 +19,7 @@ //! - [x] [HashTape](tape::hash_tape::HashTape) #![cfg_attr(not(feature = "std"), no_std)] +#![allow(clippy::new_ret_no_self)] #[cfg(feature = "alloc")] extern crate alloc; diff --git a/core/src/mem/tape/tape.rs b/core/src/mem/tape/tape.rs index 5b2d5f1..38c18de 100644 --- a/core/src/mem/tape/tape.rs +++ b/core/src/mem/tape/tape.rs @@ -8,10 +8,11 @@ use core::cell::Cell; #[cfg(feature = "alloc")] use alloc::vec::Vec; -/// In-line with the Turing machine model, the [`StdTape`] is a one-dimensional surface evenly -/// divided into cells capable of storing symbols. The tape is infinite in both directions -/// allowing the head, or actor, to move without bounds, extending the tape as needed. -/// +/// # [StdTape] +/// +/// [StdTae] is a basic implementation of a tape, a one-dimensional surface evenly divided into +/// cells capable of storing symbols. The tape is infinite in both directions allowing the +/// head, or actor, to move without bounds, extending the tape as needed. /// /// Here, the tape 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 diff --git a/core/src/state/state.rs b/core/src/state/state.rs index ebffb22..ff53fba 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -27,7 +27,7 @@ impl State { /// /// # Saftey /// - /// * + /// This method is unsafe because it is up to the caller to ensure that the cast is valid. pub unsafe fn cast(self) -> State { State(core::ptr::read(&self.0 as *const Q as *const R)) } diff --git a/core/src/types/direction.rs b/core/src/types/direction.rs index 029de44..a5d082d 100644 --- a/core/src/types/direction.rs +++ b/core/src/types/direction.rs @@ -3,6 +3,7 @@ Contrib: FL03 */ /// [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, diff --git a/core/src/types/tail.rs b/core/src/types/tail.rs index 89090d4..8bbef67 100644 --- a/core/src/types/tail.rs +++ b/core/src/types/tail.rs @@ -219,6 +219,12 @@ mod builder { symbol: Option, } + impl Default for TailBuilder { + fn default() -> Self { + Self::new() + } + } + impl TailBuilder { pub fn new() -> Self { Self { From d197c01c4c0a1460079797ded1128e93fca2c9fc Mon Sep 17 00:00:00 2001 From: FL03 Date: Sat, 7 Sep 2024 13:29:20 -0500 Subject: [PATCH 27/27] update Signed-off-by: FL03 --- rstm/src/exp/mod.rs | 13 +++ rstm/src/{models => exp/model}/base.rs | 101 ++++++++---------- rstm/src/{models => exp/model}/mod.rs | 5 +- .../{models/engine.rs => exp/model/tmh.rs} | 0 rstm/src/exp/shift/direction.rs | 10 ++ rstm/src/{ => exp}/shift/mod.rs | 8 +- rstm/src/lib.rs | 13 +-- rstm/src/shift/direction.rs | 78 -------------- 8 files changed, 83 insertions(+), 145 deletions(-) create mode 100644 rstm/src/exp/mod.rs rename rstm/src/{models => exp/model}/base.rs (54%) rename rstm/src/{models => exp/model}/mod.rs (67%) rename rstm/src/{models/engine.rs => exp/model/tmh.rs} (100%) create mode 100644 rstm/src/exp/shift/direction.rs rename rstm/src/{ => exp}/shift/mod.rs (74%) delete mode 100644 rstm/src/shift/direction.rs diff --git a/rstm/src/exp/mod.rs b/rstm/src/exp/mod.rs new file mode 100644 index 0000000..1c6e687 --- /dev/null +++ b/rstm/src/exp/mod.rs @@ -0,0 +1,13 @@ +/* + Appellation: exp + Contrib: FL03 +*/ +//! # Experimental (exp) +//! +//! +#![allow(unused)] + +#[doc(hidden)] +pub mod model; +#[doc(hidden)] +pub mod shift; diff --git a/rstm/src/models/base.rs b/rstm/src/exp/model/base.rs similarity index 54% rename from rstm/src/models/base.rs rename to rstm/src/exp/model/base.rs index 5f92b3a..4b11a43 100644 --- a/rstm/src/models/base.rs +++ b/rstm/src/exp/model/base.rs @@ -2,9 +2,9 @@ Appellation: tm Contrib: FL03 */ -use crate::prelude::{Error, Head, StdTape, Symbolic, Tail}; +use crate::prelude::{Direction, Error, Head, Rule, StdTape, Symbolic, Tail}; use crate::rules::Ruleset; -use crate::state::{halt::HaltState, State}; +use crate::state::{halt::HaltState, RawState, State}; /// # Turing Machine ([StdTm]) /// @@ -13,55 +13,44 @@ use crate::state::{halt::HaltState, State}; /// 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 StdTM { - pub(crate) program: Ruleset, - pub(crate) state: HaltState, - pub(crate) tape: StdTape, +pub struct StdTM { + pub(crate) program: Ruleset, + pub(crate) state: State>, + pub(crate) tape: StdTape, } -impl StdTM { - pub fn new(program: Ruleset, tape: StdTape) -> Self +impl StdTM { + pub fn new(rules: impl IntoIterator>, tape: StdTape) -> Self where - Q: Clone + Default, - S: Default, + A: Default, { - let state = program - .initial_state() - .map(|q| q.cloned()) - .unwrap_or_default(); StdTM { - program, - state: HaltState::state(state), + program: Ruleset::from_iter(rules), + state: State::none(), tape, } } /// Returns an immutable reference to the [program](Program) - pub const fn program(&self) -> &Ruleset { + pub const fn program(&self) -> &Ruleset { &self.program } /// Creates a new instance of a [head](Head) from references to the current state and symbol; - pub fn read(&self) -> Option> { + pub fn read(&self) -> Option, &'_ A>> { self.tape() .read() .ok() .map(|symbol| Head::new(self.state(), symbol)) } - /// Returns an instance of the [state](State) with an immutable - /// reference to the internal data - pub fn state(&self) -> State<&'_ Q> { - self.state.as_state() - } - /// 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.as_mut_state() + + pub fn state(&self) -> State<&Option> { + self.state.to_ref() } /// Returns an immutable reference to the [tape](StdTape) - pub const fn tape(&self) -> &StdTape { + pub const fn tape(&self) -> &StdTape { &self.tape } /// Returns a mutable reference to the [tape](StdTape) - pub fn tape_mut(&mut self) -> &mut StdTape { + pub fn tape_mut(&mut self) -> &mut StdTape { &mut self.tape } /// Runs the program until the @@ -74,7 +63,7 @@ impl StdTM { pub fn execute(mut self) -> Result<(), Error> where Q: Clone + PartialEq + 'static, - S: Symbolic, + A: Symbolic, { #[cfg(feature = "tracing")] tracing::trace!("Executing the program..."); @@ -96,41 +85,41 @@ impl StdTM { } } + fn handle(&mut self, direction: Direction, state: State>, symbol: A) { + self.tape.update(direction, symbol); + self.state = state.into(); + } + #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "process", target = "turing") )] - fn process(&mut self) -> Option> + fn process(&mut self) -> Option> where Q: Clone + PartialEq, - S: Clone + PartialEq, + A: Clone + PartialEq, { #[cfg(feature = "tracing")] tracing::trace!("Processing the current instruction..."); - // Get the first instruction for the current head - if let Some(Tail { - direction, - state, - symbol, - }) = self.program.get_ref(self.read()?) - { - // - self.tape.update(direction, symbol.clone()); - self.state = state.cloned().into(); - return Some(Head::new(state, symbol)); + let csymbol = self.tape.read().ok()?; + if let Some(cstate) = self.state().get() { + if let Some(Tail { + direction, + state, + symbol, + }) = self.program.get(State(cstate), csymbol) + { + // + self.tape.update(*direction, symbol.clone()); + self.state = state.clone().map(Some); + return Some(Head::new(State(state), symbol)); + } + unreachable!("No instruction found for the current head") + } else { + #[cfg(feature = "tracing")] + tracing::trace!("Head is halted, terminating execution..."); + return None; } - unreachable!("No instruction found for the current head") - } -} - -impl core::iter::Iterator for StdTM -where - Q: Clone + PartialEq + 'static, - S: Clone + PartialEq, -{ - type Item = Head; - - fn next(&mut self) -> Option { - self.process().map(|i| i.cloned()) + } } diff --git a/rstm/src/models/mod.rs b/rstm/src/exp/model/mod.rs similarity index 67% rename from rstm/src/models/mod.rs rename to rstm/src/exp/model/mod.rs index c391e1f..8137aea 100644 --- a/rstm/src/models/mod.rs +++ b/rstm/src/exp/model/mod.rs @@ -3,11 +3,12 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::base::StdTM; +pub use self::{base::StdTM, tmh::TMH}; pub mod base; -pub mod engine; +pub mod tmh; pub(crate) mod prelude { pub use super::base::StdTM; + pub use super::tmh::TMH; } diff --git a/rstm/src/models/engine.rs b/rstm/src/exp/model/tmh.rs similarity index 100% rename from rstm/src/models/engine.rs rename to rstm/src/exp/model/tmh.rs diff --git a/rstm/src/exp/shift/direction.rs b/rstm/src/exp/shift/direction.rs new file mode 100644 index 0000000..8f5192c --- /dev/null +++ b/rstm/src/exp/shift/direction.rs @@ -0,0 +1,10 @@ +/* + Appellation: direction + Contrib: FL03 +*/ +use crate::prelude::Direction; + +pub struct LinearShift { + pub(crate) direction: Direction, + pub(crate) value: T, +} \ No newline at end of file diff --git a/rstm/src/shift/mod.rs b/rstm/src/exp/shift/mod.rs similarity index 74% rename from rstm/src/shift/mod.rs rename to rstm/src/exp/shift/mod.rs index 236eddf..0462f19 100644 --- a/rstm/src/shift/mod.rs +++ b/rstm/src/exp/shift/mod.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::direction::{LinearShift, ShiftDirection}; +pub use self::direction::*; pub(crate) mod direction; @@ -20,3 +20,9 @@ pub trait Shift { fn shift(&self, step: T) -> Self::Output; } + +pub trait ApplyOnce where F: FnOnce(T) -> Self::Output { + type Output; + + fn apply(&self, f: F, args: T) -> F::Output; +} \ No newline at end of file diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index abd0c3f..80cee9c 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -8,22 +8,19 @@ //! The crate is designed to be flexible and easy to use while preserving the abstract nature //! of the models. -// #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), no_std)] +#![crate_name = "rstm"] +#![crate_type = "lib"] + #[cfg(feature = "alloc")] extern crate alloc; -#[doc(inline)] -pub use self::models::StdTM; #[doc(inline)] pub use rstm_core::*; #[doc(hidden)] -pub mod models; -#[doc(hidden)] -pub mod shift; +pub mod exp; pub mod prelude { - pub use super::models::prelude::*; - pub use rstm_core::prelude::*; } diff --git a/rstm/src/shift/direction.rs b/rstm/src/shift/direction.rs deleted file mode 100644 index 1352fb7..0000000 --- a/rstm/src/shift/direction.rs +++ /dev/null @@ -1,78 +0,0 @@ -/* - Appellation: direction - Contrib: FL03 -*/ - -/// [LinearShift] -#[derive( - Clone, - Copy, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - strum::EnumDiscriminants, - strum::EnumCount, - strum::EnumIs, -)] -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize, serde::Serialize), - strum_discriminants(derive(serde::Deserialize, serde::Serialize)) -)] -#[strum(serialize_all = "lowercase")] -#[strum_discriminants( - name(ShiftDirection), - derive( - Hash, - Ord, - PartialOrd, - strum::AsRefStr, - strum::Display, - strum::EnumCount, - strum::EnumIs, - strum::EnumIter, - strum::VariantNames, - ), - strum(serialize_all = "lowercase") -)] -pub enum LinearShift { - /// Represents a single left shift - #[cfg_attr( - feature = "serde", - serde( - alias = "left", - alias = "l", - alias = "L", - alias = "LEFT", - alias = "Left" - ) - )] - Left(T), - #[cfg_attr( - feature = "serde", - serde( - alias = "right", - alias = "r", - alias = "R", - alias = "RIGHT", - alias = "Right" - ) - )] - /// Represents a single right shift - Right(T), - #[cfg_attr( - feature = "serde", - serde( - alias = "stay", - alias = "s", - alias = "S", - alias = "STAY", - alias = "Stay" - ) - )] - /// Represents no movement - Stay(T), -}