mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
simplify the <S> generic so it's not an Rc
This commit is contained in:
parent
af4b0d0add
commit
d68233e0b1
10 changed files with 295 additions and 53 deletions
|
@ -1,4 +1,7 @@
|
|||
use crate::{context::CommandContext, modifier::RedirectModifier, tree::CommandNode};
|
||||
use crate::{
|
||||
context::CommandContext, exceptions::command_syntax_exception::CommandSyntaxException,
|
||||
modifier::RedirectModifier, tree::CommandNode,
|
||||
};
|
||||
|
||||
use super::{literal_argument_builder::Literal, required_argument_builder::Argument};
|
||||
use std::{any::Any, cell::RefCell, fmt::Debug, rc::Rc};
|
||||
|
@ -10,8 +13,7 @@ pub enum ArgumentBuilderType {
|
|||
}
|
||||
|
||||
/// A node that hasn't yet been built.
|
||||
#[derive(Clone)]
|
||||
pub struct ArgumentBuilder<S: Any + Clone> {
|
||||
pub struct ArgumentBuilder<S> {
|
||||
arguments: CommandNode<S>,
|
||||
|
||||
command: Option<Rc<dyn Fn(&CommandContext<S>) -> i32>>,
|
||||
|
@ -19,11 +21,24 @@ pub struct ArgumentBuilder<S: Any + Clone> {
|
|||
target: Option<Rc<RefCell<CommandNode<S>>>>,
|
||||
|
||||
forks: bool,
|
||||
modifier: Option<Rc<dyn RedirectModifier<S>>>,
|
||||
modifier: Option<Rc<RedirectModifier<S>>>,
|
||||
}
|
||||
|
||||
impl<S> Clone for ArgumentBuilder<S> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
arguments: self.arguments.clone(),
|
||||
command: self.command.clone(),
|
||||
requirement: self.requirement.clone(),
|
||||
target: self.target.clone(),
|
||||
forks: self.forks.clone(),
|
||||
modifier: self.modifier.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A node that isn't yet built.
|
||||
impl<S: Any + Clone> ArgumentBuilder<S> {
|
||||
impl<S> ArgumentBuilder<S> {
|
||||
pub fn new(value: ArgumentBuilderType) -> Self {
|
||||
Self {
|
||||
arguments: CommandNode {
|
||||
|
@ -65,10 +80,18 @@ impl<S: Any + Clone> ArgumentBuilder<S> {
|
|||
self.forward(target, None, false)
|
||||
}
|
||||
|
||||
pub fn fork(
|
||||
&mut self,
|
||||
target: Rc<RefCell<CommandNode<S>>>,
|
||||
modifier: Rc<RedirectModifier<S>>,
|
||||
) -> Self {
|
||||
self.forward(target, Some(modifier), true)
|
||||
}
|
||||
|
||||
pub fn forward(
|
||||
&mut self,
|
||||
target: Rc<RefCell<CommandNode<S>>>,
|
||||
modifier: Option<Rc<dyn RedirectModifier<S>>>,
|
||||
modifier: Option<Rc<RedirectModifier<S>>>,
|
||||
fork: bool,
|
||||
) -> Self {
|
||||
if !self.arguments.children.is_empty() {
|
||||
|
@ -99,7 +122,7 @@ impl<S: Any + Clone> ArgumentBuilder<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> Debug for ArgumentBuilder<S> {
|
||||
impl<S> Debug for ArgumentBuilder<S> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ArgumentBuilder")
|
||||
.field("arguments", &self.arguments)
|
||||
|
|
|
@ -21,6 +21,6 @@ impl From<Literal> for ArgumentBuilderType {
|
|||
}
|
||||
|
||||
/// Shortcut for creating a new literal builder node.
|
||||
pub fn literal<S: Any + Clone>(value: &str) -> ArgumentBuilder<S> {
|
||||
pub fn literal<S>(value: &str) -> ArgumentBuilder<S> {
|
||||
ArgumentBuilder::new(ArgumentBuilderType::Literal(Literal::new(value)))
|
||||
}
|
||||
|
|
|
@ -41,6 +41,6 @@ impl Debug for Argument {
|
|||
}
|
||||
|
||||
/// Shortcut for creating a new argument builder node.
|
||||
pub fn argument<S: Any + Clone>(name: &str, parser: impl Parser + 'static) -> ArgumentBuilder<S> {
|
||||
pub fn argument<S>(name: &str, parser: impl Parser + 'static) -> ArgumentBuilder<S> {
|
||||
ArgumentBuilder::new(Argument::new(name, Rc::new(parser)).into())
|
||||
}
|
||||
|
|
|
@ -1,25 +1,43 @@
|
|||
use std::{any::Any, cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
dispatcher::CommandDispatcher, modifier::RedirectModifier, string_range::StringRange,
|
||||
tree::CommandNode,
|
||||
dispatcher::CommandDispatcher,
|
||||
modifier::RedirectModifier,
|
||||
string_range::StringRange,
|
||||
tree::{CommandNode, ParsedCommandNode},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CommandContextBuilder<S: Any + Clone> {
|
||||
pub struct CommandContextBuilder<S> {
|
||||
pub arguments: HashMap<String, ParsedArgument>,
|
||||
pub root: Rc<RefCell<CommandNode<S>>>,
|
||||
pub nodes: Vec<Rc<CommandNode<S>>>,
|
||||
pub nodes: Vec<ParsedCommandNode<S>>,
|
||||
pub dispatcher: Rc<CommandDispatcher<S>>,
|
||||
pub source: Rc<S>,
|
||||
pub command: Option<Rc<dyn Fn(&CommandContext<S>) -> i32>>,
|
||||
pub child: Option<Rc<CommandContextBuilder<S>>>,
|
||||
pub range: StringRange,
|
||||
pub modifier: Option<Rc<dyn RedirectModifier<S>>>,
|
||||
pub modifier: Option<Rc<RedirectModifier<S>>>,
|
||||
pub forks: bool,
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> CommandContextBuilder<S> {
|
||||
impl<S> Clone for CommandContextBuilder<S> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
arguments: self.arguments.clone(),
|
||||
root: self.root.clone(),
|
||||
nodes: self.nodes.clone(),
|
||||
dispatcher: self.dispatcher.clone(),
|
||||
source: self.source.clone(),
|
||||
command: self.command.clone(),
|
||||
child: self.child.clone(),
|
||||
range: self.range.clone(),
|
||||
modifier: self.modifier.clone(),
|
||||
forks: self.forks.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> CommandContextBuilder<S> {
|
||||
// CommandDispatcher<S> dispatcher, final S source, final CommandNode<S> rootNode, final int start
|
||||
pub fn new(
|
||||
dispatcher: Rc<CommandDispatcher<S>>,
|
||||
|
@ -58,11 +76,14 @@ impl<S: Any + Clone> CommandContextBuilder<S> {
|
|||
self.arguments.insert(name.to_string(), argument);
|
||||
self
|
||||
}
|
||||
pub fn with_node(&mut self, node: Rc<CommandNode<S>>, range: StringRange) -> &Self {
|
||||
self.nodes.push(node.clone());
|
||||
pub fn with_node(&mut self, node: Rc<RefCell<CommandNode<S>>>, range: StringRange) -> &Self {
|
||||
self.nodes.push(ParsedCommandNode {
|
||||
node: node.clone(),
|
||||
range: range.clone(),
|
||||
});
|
||||
self.range = StringRange::encompassing(&self.range, &range);
|
||||
self.modifier = node.modifier.clone();
|
||||
self.forks = node.forks;
|
||||
self.modifier = node.borrow().modifier.clone();
|
||||
self.forks = node.borrow().forks;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -82,12 +103,12 @@ impl<S: Any + Clone> CommandContextBuilder<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> Debug for CommandContextBuilder<S> {
|
||||
impl<S> Debug for CommandContextBuilder<S> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("CommandContextBuilder")
|
||||
// .field("arguments", &self.arguments)
|
||||
.field("root", &self.root)
|
||||
.field("nodes", &self.nodes)
|
||||
// .field("nodes", &self.nodes)
|
||||
// .field("dispatcher", &self.dispatcher)
|
||||
// .field("source", &self.source)
|
||||
// .field("command", &self.command)
|
||||
|
@ -105,22 +126,38 @@ pub struct ParsedArgument {
|
|||
pub result: Rc<dyn Any>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
/// A built `CommandContextBuilder`.
|
||||
pub struct CommandContext<S: Any + Clone> {
|
||||
pub struct CommandContext<S> {
|
||||
pub source: Rc<S>,
|
||||
pub input: String,
|
||||
pub arguments: HashMap<String, ParsedArgument>,
|
||||
pub command: Option<Rc<dyn Fn(&CommandContext<S>) -> i32>>,
|
||||
pub root_node: Rc<RefCell<CommandNode<S>>>,
|
||||
pub nodes: Vec<Rc<CommandNode<S>>>,
|
||||
pub nodes: Vec<ParsedCommandNode<S>>,
|
||||
pub range: StringRange,
|
||||
pub child: Option<Rc<CommandContext<S>>>,
|
||||
pub modifier: Option<Rc<dyn RedirectModifier<S>>>,
|
||||
pub modifier: Option<Rc<RedirectModifier<S>>>,
|
||||
pub forks: bool,
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> CommandContext<S> {
|
||||
impl<S> Clone for CommandContext<S> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
source: self.source.clone(),
|
||||
input: self.input.clone(),
|
||||
arguments: self.arguments.clone(),
|
||||
command: self.command.clone(),
|
||||
root_node: self.root_node.clone(),
|
||||
nodes: self.nodes.clone(),
|
||||
range: self.range.clone(),
|
||||
child: self.child.clone(),
|
||||
modifier: self.modifier.clone(),
|
||||
forks: self.forks.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> CommandContext<S> {
|
||||
pub fn copy_for(&self, source: Rc<S>) -> Self {
|
||||
if Rc::ptr_eq(&source, &self.source) {
|
||||
return self.clone();
|
||||
|
|
|
@ -13,12 +13,12 @@ use std::{
|
|||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CommandDispatcher<S: Any + Clone> {
|
||||
pub struct CommandDispatcher<S> {
|
||||
root: Rc<RefCell<CommandNode<S>>>,
|
||||
_marker: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> CommandDispatcher<S> {
|
||||
impl<S> CommandDispatcher<S> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
root: Rc::new(RefCell::new(CommandNode::default())),
|
||||
|
@ -32,10 +32,10 @@ impl<S: Any + Clone> CommandDispatcher<S> {
|
|||
build
|
||||
}
|
||||
|
||||
pub fn parse(&self, command: StringReader, source: S) -> ParseResults<S> {
|
||||
pub fn parse(&self, command: StringReader, source: Rc<S>) -> ParseResults<S> {
|
||||
let context = CommandContextBuilder::new(
|
||||
Rc::new(self.clone()),
|
||||
Rc::new(source),
|
||||
source,
|
||||
self.root.clone(),
|
||||
command.cursor(),
|
||||
);
|
||||
|
@ -153,7 +153,11 @@ impl<S: Any + Clone> CommandDispatcher<S> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn execute(&self, input: StringReader, source: S) -> Result<i32, CommandSyntaxException> {
|
||||
pub fn execute(
|
||||
&self,
|
||||
input: StringReader,
|
||||
source: Rc<S>,
|
||||
) -> Result<i32, CommandSyntaxException> {
|
||||
let parse = self.parse(input, source);
|
||||
Self::execute_parsed(parse)
|
||||
}
|
||||
|
@ -191,7 +195,7 @@ impl<S: Any + Clone> CommandDispatcher<S> {
|
|||
found_command = true;
|
||||
let modifier = &context.modifier;
|
||||
if let Some(modifier) = modifier {
|
||||
let results = modifier.apply(context);
|
||||
let results = modifier(context);
|
||||
if let Ok(results) = results {
|
||||
if !results.is_empty() {
|
||||
next.extend(results.iter().map(|s| child.copy_for(s.clone())));
|
||||
|
@ -235,7 +239,7 @@ impl<S: Any + Clone> CommandDispatcher<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> Clone for CommandDispatcher<S> {
|
||||
impl<S> Clone for CommandDispatcher<S> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
root: self.root.clone(),
|
||||
|
@ -244,11 +248,13 @@ impl<S: Any + Clone> Clone for CommandDispatcher<S> {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
builder::{literal_argument_builder::literal, required_argument_builder::argument},
|
||||
modifier::RedirectModifier,
|
||||
parsers::integer,
|
||||
};
|
||||
|
||||
|
@ -655,4 +661,145 @@ mod tests {
|
|||
100
|
||||
);
|
||||
}
|
||||
// @Test
|
||||
// public void testExecuteRedirectedMultipleTimes() throws Exception {
|
||||
// final LiteralCommandNode<Object> concreteNode = subject.register(literal("actual").executes(command));
|
||||
// final LiteralCommandNode<Object> redirectNode = subject.register(literal("redirected").redirect(subject.getRoot()));
|
||||
|
||||
// final String input = "redirected redirected actual";
|
||||
|
||||
// final ParseResults<Object> parse = subject.parse(input, source);
|
||||
// assertThat(parse.getContext().getRange().get(input), equalTo("redirected"));
|
||||
// assertThat(parse.getContext().getNodes().size(), is(1));
|
||||
// assertThat(parse.getContext().getRootNode(), is(subject.getRoot()));
|
||||
// assertThat(parse.getContext().getNodes().get(0).getRange(), equalTo(parse.getContext().getRange()));
|
||||
// assertThat(parse.getContext().getNodes().get(0).getNode(), is(redirectNode));
|
||||
|
||||
// final CommandContextBuilder<Object> child1 = parse.getContext().getChild();
|
||||
// assertThat(child1, is(notNullValue()));
|
||||
// assertThat(child1.getRange().get(input), equalTo("redirected"));
|
||||
// assertThat(child1.getNodes().size(), is(1));
|
||||
// assertThat(child1.getRootNode(), is(subject.getRoot()));
|
||||
// assertThat(child1.getNodes().get(0).getRange(), equalTo(child1.getRange()));
|
||||
// assertThat(child1.getNodes().get(0).getNode(), is(redirectNode));
|
||||
|
||||
// final CommandContextBuilder<Object> child2 = child1.getChild();
|
||||
// assertThat(child2, is(notNullValue()));
|
||||
// assertThat(child2.getRange().get(input), equalTo("actual"));
|
||||
// assertThat(child2.getNodes().size(), is(1));
|
||||
// assertThat(child2.getRootNode(), is(subject.getRoot()));
|
||||
// assertThat(child2.getNodes().get(0).getRange(), equalTo(child2.getRange()));
|
||||
// assertThat(child2.getNodes().get(0).getNode(), is(concreteNode));
|
||||
|
||||
// assertThat(subject.execute(parse), is(42));
|
||||
// verify(command).run(any(CommandContext.class));
|
||||
// }
|
||||
#[test]
|
||||
fn test_execute_redirected_multiple_times() {
|
||||
let mut subject = CommandDispatcher::new();
|
||||
|
||||
let concrete_node = subject.register(literal("actual").executes(|_| 42));
|
||||
let root = subject.root.clone();
|
||||
let redirect_node = subject.register(literal("redirected").redirect(root.clone()));
|
||||
|
||||
let input = "redirected redirected actual";
|
||||
|
||||
let parse = subject.parse(input.into(), Rc::new(CommandSource {}));
|
||||
assert_eq!(parse.context.range.get(input), "redirected");
|
||||
assert_eq!(parse.context.nodes.len(), 1);
|
||||
assert_eq!(parse.context.root, root);
|
||||
assert_eq!(parse.context.nodes[0].range, parse.context.range);
|
||||
assert_eq!(parse.context.nodes[0].node, redirect_node);
|
||||
|
||||
let child1 = parse.context.child.clone();
|
||||
assert!(child1.is_some());
|
||||
assert_eq!(child1.clone().unwrap().range.get(input), "redirected");
|
||||
assert_eq!(child1.clone().unwrap().nodes.len(), 1);
|
||||
assert_eq!(child1.clone().unwrap().root, root);
|
||||
assert_eq!(
|
||||
child1.clone().unwrap().nodes[0].range,
|
||||
child1.clone().unwrap().range
|
||||
);
|
||||
assert_eq!(child1.clone().unwrap().nodes[0].node, redirect_node);
|
||||
|
||||
let child2 = child1.unwrap().child.clone();
|
||||
assert!(child2.is_some());
|
||||
assert_eq!(child2.clone().unwrap().range.get(input), "actual");
|
||||
assert_eq!(child2.clone().unwrap().nodes.len(), 1);
|
||||
assert_eq!(child2.clone().unwrap().root, root);
|
||||
assert_eq!(
|
||||
child2.clone().unwrap().nodes[0].range,
|
||||
child2.clone().unwrap().range
|
||||
);
|
||||
assert_eq!(child2.clone().unwrap().nodes[0].node, concrete_node);
|
||||
|
||||
assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 42);
|
||||
}
|
||||
// @Test
|
||||
// public void testExecuteRedirected() throws Exception {
|
||||
// final RedirectModifier<Object> modifier = mock(RedirectModifier.class);
|
||||
// final Object source1 = new Object();
|
||||
// final Object source2 = new Object();
|
||||
|
||||
// when(modifier.apply(argThat(hasProperty("source", is(source))))).thenReturn(Lists.newArrayList(source1, source2));
|
||||
|
||||
// final LiteralCommandNode<Object> concreteNode = subject.register(literal("actual").executes(command));
|
||||
// final LiteralCommandNode<Object> redirectNode = subject.register(literal("redirected").fork(subject.getRoot(), modifier));
|
||||
|
||||
// final String input = "redirected actual";
|
||||
// final ParseResults<Object> parse = subject.parse(input, source);
|
||||
// assertThat(parse.getContext().getRange().get(input), equalTo("redirected"));
|
||||
// assertThat(parse.getContext().getNodes().size(), is(1));
|
||||
// assertThat(parse.getContext().getRootNode(), equalTo(subject.getRoot()));
|
||||
// assertThat(parse.getContext().getNodes().get(0).getRange(), equalTo(parse.getContext().getRange()));
|
||||
// assertThat(parse.getContext().getNodes().get(0).getNode(), is(redirectNode));
|
||||
// assertThat(parse.getContext().getSource(), is(source));
|
||||
|
||||
// final CommandContextBuilder<Object> parent = parse.getContext().getChild();
|
||||
// assertThat(parent, is(notNullValue()));
|
||||
// assertThat(parent.getRange().get(input), equalTo("actual"));
|
||||
// assertThat(parent.getNodes().size(), is(1));
|
||||
// assertThat(parse.getContext().getRootNode(), equalTo(subject.getRoot()));
|
||||
// assertThat(parent.getNodes().get(0).getRange(), equalTo(parent.getRange()));
|
||||
// assertThat(parent.getNodes().get(0).getNode(), is(concreteNode));
|
||||
// assertThat(parent.getSource(), is(source));
|
||||
|
||||
// assertThat(subject.execute(parse), is(2));
|
||||
// verify(command).run(argThat(hasProperty("source", is(source1))));
|
||||
// verify(command).run(argThat(hasProperty("source", is(source2))));
|
||||
// }
|
||||
#[test]
|
||||
fn test_execute_redirected() {
|
||||
let mut subject = CommandDispatcher::new();
|
||||
|
||||
let source1 = Rc::new(CommandSource {});
|
||||
let source2 = Rc::new(CommandSource {});
|
||||
|
||||
let modifier = move |source: &CommandContext<Rc<CommandSource>>| -> Result<Vec<Rc<CommandSource>>, CommandSyntaxException> {
|
||||
Ok(vec![source1.clone(), source2.clone()])
|
||||
};
|
||||
|
||||
let concrete_node = subject.register(literal("actual").executes(|_| 42));
|
||||
let redirect_node =
|
||||
subject.register(literal("redirected").fork(subject.root.clone(), modifier));
|
||||
|
||||
let input = "redirected actual";
|
||||
let parse = subject.parse(input.into(), Rc::new(CommandSource {}));
|
||||
assert_eq!(parse.context.range.get(input), "redirected");
|
||||
assert_eq!(parse.context.nodes.len(), 1);
|
||||
assert_eq!(parse.context.root, subject.root);
|
||||
assert_eq!(parse.context.nodes[0].range, parse.context.range);
|
||||
assert_eq!(parse.context.nodes[0].node, redirect_node);
|
||||
|
||||
let parent = parse.context.child.clone();
|
||||
assert!(parent.is_some());
|
||||
let parent = parent.unwrap();
|
||||
assert_eq!(parent.range.get(input), "actual");
|
||||
assert_eq!(parent.nodes.len(), 1);
|
||||
assert_eq!(parse.context.root, subject.root);
|
||||
assert_eq!(parent.nodes[0].range, parent.range);
|
||||
assert_eq!(parent.nodes[0].node, concrete_node);
|
||||
// assert_eq!(parent.source, Rc::new(CommandSource {}));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -27,7 +27,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let mut dispatcher = CommandDispatcher::<Rc<CommandSourceStack>>::new();
|
||||
let mut dispatcher = CommandDispatcher::<CommandSourceStack>::new();
|
||||
|
||||
let source = Rc::new(CommandSourceStack {
|
||||
player: "player".to_string(),
|
||||
|
|
|
@ -4,6 +4,9 @@ use crate::{
|
|||
context::CommandContext, exceptions::command_syntax_exception::CommandSyntaxException,
|
||||
};
|
||||
|
||||
pub trait RedirectModifier<S: Any + Clone> {
|
||||
fn apply(&self, context: &CommandContext<S>) -> Result<Vec<Rc<S>>, CommandSyntaxException>;
|
||||
}
|
||||
// pub trait RedirectModifier<S> {
|
||||
// fn apply(&self, context: &CommandContext<S>) -> Result<Vec<S>, CommandSyntaxException>;
|
||||
// }
|
||||
|
||||
pub type RedirectModifier<S> =
|
||||
dyn Fn(&CommandContext<S>) -> Result<Vec<Rc<S>>, CommandSyntaxException>;
|
||||
|
|
|
@ -4,13 +4,13 @@ use crate::{
|
|||
};
|
||||
use std::{any::Any, collections::HashMap, fmt::Debug, rc::Rc};
|
||||
|
||||
pub struct ParseResults<S: Any + Clone> {
|
||||
pub struct ParseResults<S> {
|
||||
pub context: CommandContextBuilder<S>,
|
||||
pub reader: StringReader,
|
||||
pub exceptions: HashMap<Rc<CommandNode<S>>, CommandSyntaxException>,
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> Debug for ParseResults<S> {
|
||||
impl<S> Debug for ParseResults<S> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ParseResults")
|
||||
.field("context", &self.context)
|
||||
|
|
|
@ -49,7 +49,7 @@ impl Parser for Integer {
|
|||
pub fn integer() -> impl Parser {
|
||||
Integer::default()
|
||||
}
|
||||
pub fn get_integer<S: Any + Clone>(context: &CommandContext<S>, name: &str) -> Option<i32> {
|
||||
pub fn get_integer<S>(context: &CommandContext<S>, name: &str) -> Option<i32> {
|
||||
context
|
||||
.argument(name)
|
||||
.unwrap()
|
||||
|
|
|
@ -14,9 +14,8 @@ use crate::{
|
|||
use std::{any::Any, cell::RefCell, collections::BTreeMap, fmt::Debug, hash::Hash, ptr, rc::Rc};
|
||||
|
||||
/// An ArgumentBuilder that has been built.
|
||||
#[derive(Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct CommandNode<S: Any + Clone> {
|
||||
pub struct CommandNode<S> {
|
||||
pub value: ArgumentBuilderType,
|
||||
|
||||
// we use BTreeMap instead of HashMap because it can be hashed
|
||||
|
@ -28,10 +27,41 @@ pub struct CommandNode<S: Any + Clone> {
|
|||
pub requirement: Rc<dyn Fn(Rc<S>) -> bool>,
|
||||
pub redirect: Option<Rc<RefCell<CommandNode<S>>>>,
|
||||
pub forks: bool,
|
||||
pub modifier: Option<Rc<dyn RedirectModifier<S>>>,
|
||||
pub modifier: Option<Rc<RedirectModifier<S>>>,
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> CommandNode<S> {
|
||||
impl<S> Clone for CommandNode<S> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
value: self.value.clone(),
|
||||
children: self.children.clone(),
|
||||
literals: self.literals.clone(),
|
||||
arguments: self.arguments.clone(),
|
||||
command: self.command.clone(),
|
||||
requirement: self.requirement.clone(),
|
||||
redirect: self.redirect.clone(),
|
||||
forks: self.forks.clone(),
|
||||
modifier: self.modifier.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParsedCommandNode<S> {
|
||||
pub node: Rc<RefCell<CommandNode<S>>>,
|
||||
pub range: StringRange,
|
||||
}
|
||||
|
||||
impl<S> Clone for ParsedCommandNode<S> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
node: self.node.clone(),
|
||||
range: self.range.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> CommandNode<S> {
|
||||
/// Gets the literal, or panics. You should use match if you're not certain about the type.
|
||||
pub fn literal(&self) -> &Literal {
|
||||
match self.value {
|
||||
|
@ -126,7 +156,7 @@ impl<S: Any + Clone> CommandNode<S> {
|
|||
};
|
||||
|
||||
context_builder.with_argument(&argument.name, parsed.clone());
|
||||
context_builder.with_node(Rc::new(self.clone()), parsed.range);
|
||||
context_builder.with_node(Rc::new(RefCell::new(self.clone())), parsed.range);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -135,8 +165,10 @@ impl<S: Any + Clone> CommandNode<S> {
|
|||
let end = self.parse(reader);
|
||||
|
||||
if let Some(end) = end {
|
||||
context_builder
|
||||
.with_node(Rc::new(self.clone()), StringRange::between(start, end));
|
||||
context_builder.with_node(
|
||||
Rc::new(RefCell::new(self.clone())),
|
||||
StringRange::between(start, end),
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -177,7 +209,7 @@ impl<S: Any + Clone> CommandNode<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> Debug for CommandNode<S> {
|
||||
impl<S> Debug for CommandNode<S> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("CommandNode")
|
||||
.field("value", &self.value)
|
||||
|
@ -191,7 +223,7 @@ impl<S: Any + Clone> Debug for CommandNode<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> Default for CommandNode<S> {
|
||||
impl<S> Default for CommandNode<S> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
value: ArgumentBuilderType::Literal(Literal::default()),
|
||||
|
@ -209,7 +241,7 @@ impl<S: Any + Clone> Default for CommandNode<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> Hash for CommandNode<S> {
|
||||
impl<S> Hash for CommandNode<S> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
// hash the children
|
||||
for (k, v) in &self.children {
|
||||
|
@ -221,7 +253,7 @@ impl<S: Any + Clone> Hash for CommandNode<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Any + Clone> PartialEq for CommandNode<S> {
|
||||
impl<S> PartialEq for CommandNode<S> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.children != other.children {
|
||||
return false;
|
||||
|
@ -242,4 +274,4 @@ impl<S: Any + Clone> PartialEq for CommandNode<S> {
|
|||
true
|
||||
}
|
||||
}
|
||||
impl<S: Any + Clone> Eq for CommandNode<S> {}
|
||||
impl<S> Eq for CommandNode<S> {}
|
||||
|
|
Loading…
Add table
Reference in a new issue