Skip to content

Commit

Permalink
OneOf plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
30bit committed Mar 21, 2024
1 parent 4593146 commit f1244da
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 16 deletions.
9 changes: 5 additions & 4 deletions Cargo.toml
Expand Up @@ -2,7 +2,7 @@
members = [".", "choco_macros", "chocobrew", "rewrite"]

[workspace.package]
version = "0.2.2"
version = "0.3.0"
authors = ["Artur Helmanau <m30bit@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
Expand All @@ -21,9 +21,10 @@ edition.workspace = true
repository.workspace = true

[workspace.dependencies]
choco = { version = "=0.2.2", path = "." }
petgraph = { version = "0.6.4", default-features = false }
bitflags = "2.4.2"
choco = { version = "=0.3.0", path = "." }
choco_macros = { version = "=0.3.0", path = "choco_macros" }
petgraph = { version = "0.6.4", default-features = false }
bitflags = "2.4.2"

[dependencies]
petgraph.workspace = true
Expand Down
18 changes: 13 additions & 5 deletions rewrite/Cargo.toml
@@ -1,9 +1,17 @@
[package]
name = "rewrite"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
name = "rewrite"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true

[features]
default = ["std", "macros", "plugins"]
std = []
macros = ["choco_macros", "plugins"]
plugins = ["petgraph", "std"]

[dependencies]
choco_macros = { workspace = true, optional = true }
petgraph = { workspace = true, optional = true }
95 changes: 89 additions & 6 deletions rewrite/src/core.rs
@@ -1,9 +1,10 @@
use ::core::{
any::{Any, TypeId},
iter::{FusedIterator, Peekable},
ops::Range,
str::CharIndices,
};
use std::any::{Any, TypeId};
use core::fmt;

const SIGNAL_CHAR: char = '@';

Expand All @@ -28,13 +29,52 @@ impl<'a> StrRange<'a> {
}
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct PluginError {
pub plugin: TypeId,
pub signal_range: Range<usize>,
pub msg: &'static str,
}

impl PluginError {
#[inline]
#[must_use]
pub fn new<P: Plugin>(signal: Range<usize>) -> Self {
Self {
plugin: TypeId::of::<P>(),
signal_range: signal,
msg: "",
}
}

#[inline]
#[must_use]
pub fn with_msg(mut self, msg: &'static str) -> Self {
self.msg = msg;
self
}
}

impl fmt::Display for PluginError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"signal `[{:?}]` can't be taken by plugin: {}",
self.signal_range, self.msg
)
}
}

pub type PluginResult<T> = Result<T, PluginError>;

pub trait Plugin: Any + Sized {
/// Try to process `signal`.
/// If [`Plugin`] implementation doesn't work with that `signal` return [`None`].
/// Otherwise return [`TypeId`] of the sub [`Plugin`] that successfully handled the `signal`
///
/// [`EventFlow::plugins`] of the passed `flow` parameter is supposed to contain this implementation as sub plugin.
fn take_signal<P: Plugin>(signal: StrRange, flow: EventFlow<P>) -> Option<TypeId>;
fn take_signal<P: Plugin>(signal: StrRange, flow: EventFlow<P>)
-> PluginResult<Option<TypeId>>;

/// Mutably get sub plugin. The plugin itself is considered sub plugin
#[inline]
Expand All @@ -50,8 +90,14 @@ pub trait Plugin: Any + Sized {
}

impl<T: Plugin, U: Plugin> Plugin for (T, U) {
fn take_signal<P: Plugin>(signal: StrRange, mut flow: EventFlow<P>) -> Option<TypeId> {
T::take_signal(signal.clone(), flow.clone()).or_else(|| U::take_signal(signal, flow))
fn take_signal<P: Plugin>(
signal: StrRange,
mut flow: EventFlow<P>,
) -> PluginResult<Option<TypeId>> {
T::take_signal(signal.clone(), flow.clone())
.transpose()
.or_else(|| U::take_signal(signal, flow).transpose())
.transpose()
}

fn get_sub_mut<P: Plugin>(&mut self) -> Option<&mut P> {
Expand Down Expand Up @@ -111,10 +157,36 @@ impl RawEvent {
}
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct TakenSignal {
pub range: Range<usize>,
pub plugin: TypeId,
}

impl TakenSignal {
#[inline]
#[must_use]
pub fn new<P: Plugin>(range: Range<usize>) -> Self {
Self {
range,
plugin: TypeId::of::<P>(),
}
}

/// Bundles [`Self::range`] together with original full [`str`]
#[inline]
pub fn as_of<'a>(&self, full: &'a str) -> StrRange<'a> {
StrRange {
full,
range: self.range.clone(),
}
}
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub enum Event {
Raw(RawEvent),
TakenByPlugin(TypeId),
TakenByPlugin(PluginResult<TakenSignal>),
}

#[derive(Debug)]
Expand Down Expand Up @@ -147,6 +219,11 @@ impl<'a, 's, P: Plugin> EventFlow<'a, 's, P> {
)
}

#[inline]
pub fn full_str(&self) -> &'a str {
self.raw_iter.full
}

/// Obtains an owned [`EventFlow`] with shorter lifetimes given a ref
pub fn clone<'w>(&'w mut self) -> EventFlow<'a, 'w, P> {
EventFlow {
Expand All @@ -170,7 +247,13 @@ impl<'a, 's, P: Plugin> Iterator for EventFlow<'a, 's, P> {
},
self.clone(),
)
.map(Event::TakenByPlugin)
.transpose()
.map(|result| {
Event::TakenByPlugin(result.map(|plugin| TakenSignal {
range: raw_event.range.clone(),
plugin,
}))
})
.unwrap_or_else(|| Event::Raw(raw_event)),
})
}
Expand Down
5 changes: 4 additions & 1 deletion rewrite/src/lib.rs
@@ -1 +1,4 @@
pub mod core;
#![cfg_attr(not(feature = "std"), no_std)]

pub mod core;
pub mod plugins;
6 changes: 6 additions & 0 deletions rewrite/src/plugins.rs
@@ -0,0 +1,6 @@
pub mod block;
pub mod graph;
pub mod logic;
pub mod many_of;
pub mod one_of;
pub mod vars;
Empty file added rewrite/src/plugins/block.rs
Empty file.
Empty file added rewrite/src/plugins/graph.rs
Empty file.
Empty file added rewrite/src/plugins/logic.rs
Empty file.
Empty file added rewrite/src/plugins/many_of.rs
Empty file.
40 changes: 40 additions & 0 deletions rewrite/src/plugins/one_of.rs
@@ -0,0 +1,40 @@
use crate::core::{Event, EventFlow, PluginError, StrRange};
use core::any::TypeId;

pub trait OneOf: Sized + 'static {
fn one_of(param: &str) -> Option<Self>;

fn prompt() -> &'static str;
}

pub struct Plugin<T: OneOf>(Option<T>);

impl<T: OneOf> Plugin<T> {
pub fn last(&self) -> Option<&T> {
self.0.as_ref()
}
}

impl<T: OneOf> crate::core::Plugin for Plugin<T> {
fn take_signal<P: crate::core::Plugin>(
signal: StrRange,
mut flow: EventFlow<P>,
) -> crate::core::PluginResult<Option<TypeId>> {
if signal.substr() == T::prompt() {
let err = || PluginError::new::<Self>(signal.range.clone());
let param = flow.next().ok_or_else(|| err().with_msg("no param"))?;
let raw = match param {
Event::Raw(raw) if raw.is_signal() => raw,
_ => return Err(err().with_msg("param is not a signal")),
};
let one_of = T::one_of(raw.as_of(flow.full_str()).substr());
let Some(self_) = flow.plugins.get_sub_mut::<Self>() else {
return Err(err().with_msg("can't find `Self` in `plugins`"));
};
self_.0 = one_of;
Ok(Some(TypeId::of::<Self>()))
} else {
Ok(None)
}
}
}
Empty file added rewrite/src/plugins/vars.rs
Empty file.

0 comments on commit f1244da

Please sign in to comment.