Simple process reaction
This commit is contained in:
28
src/main.rs
28
src/main.rs
@ -1,16 +1,32 @@
|
|||||||
mod rsprocess;
|
mod rsprocess;
|
||||||
use lalrpop_util::lalrpop_mod;
|
use lalrpop_util::lalrpop_mod;
|
||||||
use std::io;
|
// use std::io;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
lalrpop_mod!(grammar, "/rsprocess/grammar.rs");
|
lalrpop_mod!(grammar, "/rsprocess/grammar.rs");
|
||||||
|
|
||||||
let mut buffer = String::new();
|
// let mut buffer = String::new();
|
||||||
let i = io::stdin();
|
// let i = io::stdin();
|
||||||
i.read_line(&mut buffer).expect("Can't read stdin");
|
// i.read_line(&mut buffer).expect("Can't read stdin");
|
||||||
|
|
||||||
let result = grammar::BHMLParser::new().parse(&buffer).unwrap();
|
// let result = grammar::SetParser::new().parse(&buffer).unwrap();
|
||||||
println!("{:?}", result);
|
|
||||||
|
|
||||||
|
let reactants = grammar::SetParser::new().parse("{a}").unwrap();
|
||||||
|
let inihibitors = grammar::SetParser::new().parse("{c}").unwrap();
|
||||||
|
let products = grammar::SetParser::new().parse("{a,c}").unwrap();
|
||||||
|
|
||||||
|
let process1 = rsprocess::structure::RSreaction::from(reactants, inihibitors, products);
|
||||||
|
|
||||||
|
let reactants = grammar::SetParser::new().parse("{b}").unwrap();
|
||||||
|
let inihibitors = grammar::SetParser::new().parse("{c}").unwrap();
|
||||||
|
let products = grammar::SetParser::new().parse("{b,c}").unwrap();
|
||||||
|
|
||||||
|
let process2 = rsprocess::structure::RSreaction::from(reactants, inihibitors, products);
|
||||||
|
|
||||||
|
let current_state = grammar::SetParser::new().parse("{b}").unwrap();
|
||||||
|
|
||||||
|
println!("{:?}", rsprocess::classical::compute_all(¤t_state, vec![&process1, &process2]));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/rsprocess/classical.rs
Normal file
13
src/rsprocess/classical.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use super::structure::{RSset, RSreaction};
|
||||||
|
|
||||||
|
pub fn compute_step<'a>(current_state: &RSset<'a>, reaction: &RSreaction<'a>) -> RSset<'a> {
|
||||||
|
if reaction.enabled(current_state) {
|
||||||
|
reaction.products_clone()
|
||||||
|
} else {
|
||||||
|
RSset::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute_all<'a>(current_state: &RSset<'a>, reactions: Vec<&RSreaction<'a>>) -> RSset<'a> {
|
||||||
|
reactions.iter().fold(RSset::new(), |acc, r| acc.union(&compute_step(current_state, r)))
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use lalrpop_util::ParseError;
|
use lalrpop_util::ParseError;
|
||||||
use crate::rsprocess::{RSset, RSprocess, RSenvironment, RSassert, RSassertOp, RSBHML};
|
use crate::rsprocess::structure::{RSset, RSprocess, RSenvironment, RSassert, RSassertOp, RSBHML};
|
||||||
|
|
||||||
grammar;
|
grammar;
|
||||||
|
|
||||||
@ -29,28 +29,35 @@ pub Set: RSset<'input> = {
|
|||||||
<s: Set_of_entities> => s
|
<s: Set_of_entities> => s
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----- ContextParser -----
|
|
||||||
pub Context: Box<RSprocess<'input>> = {
|
|
||||||
"[" "]" => Box::new(RSprocess::Nill),
|
|
||||||
"[" <t: CTX_process> "]" => Box::new(t),
|
|
||||||
"[" <t: Separeted<CTX_process, ",">> "]" => Box::new(RSprocess::NondeterministicChoice{children: t})
|
|
||||||
};
|
|
||||||
|
|
||||||
CTX_process: RSprocess<'input> = {
|
|
||||||
<c: Set_of_entities> "." <k: CTX_process> => RSprocess::EntitySet{entities: c, next_process: Box::new(k)},
|
|
||||||
"(" <k: CTX_process> ")" => k,
|
|
||||||
"(" <k: Separeted<CTX_process, "+">> ")" => RSprocess::Summation{children: k},
|
|
||||||
"<" <n: Num> <k1: CTX_process> ">" "." <k: CTX_process> => RSprocess::WaitEntity{repeat: n, repeated_process: Box::new(k1), next_process: Box::new(k)},
|
|
||||||
"nil" => RSprocess::Nill,
|
|
||||||
<identifier: Literal> => RSprocess::ConstantIdentifier{identifier: identifier}
|
|
||||||
};
|
|
||||||
|
|
||||||
Set_of_entities: RSset<'input> = {
|
Set_of_entities: RSset<'input> = {
|
||||||
"{" "}" => RSset::from(vec![]),
|
"{" "}" => RSset::from(vec![]),
|
||||||
"{" <t: Literal> "}" => RSset::from(vec![t]),
|
"{" <t: Literal> "}" => RSset::from(vec![t]),
|
||||||
"{" <t: Separeted<Literal, ",">> "}" => RSset::from(t)
|
"{" <t: Separeted<Literal, ",">> "}" => RSset::from(t)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ----- ContextParser -----
|
||||||
|
pub Context: Box<RSprocess<'input>> = {
|
||||||
|
"[" "]" => Box::new(RSprocess::Nill),
|
||||||
|
"[" <t: CTX_process> "]" => Box::new(t),
|
||||||
|
"[" <t: Separeted<CTX_process, ",">> "]" =>
|
||||||
|
Box::new(RSprocess::NondeterministicChoice{ children: t })
|
||||||
|
};
|
||||||
|
|
||||||
|
CTX_process: RSprocess<'input> = {
|
||||||
|
<c: Set_of_entities> "." <k: CTX_process> =>
|
||||||
|
RSprocess::EntitySet{ entities: c, next_process: Box::new(k) },
|
||||||
|
"(" <k: CTX_process> ")" => k,
|
||||||
|
"(" <k: Separeted<CTX_process, "+">> ")" =>
|
||||||
|
RSprocess::Summation{ children: k },
|
||||||
|
"<" <n: Num> <k1: CTX_process> ">" "." <k: CTX_process> =>
|
||||||
|
RSprocess::WaitEntity{ repeat: n,
|
||||||
|
repeated_process: Box::new(k1),
|
||||||
|
next_process: Box::new(k)},
|
||||||
|
"nil" => RSprocess::Nill,
|
||||||
|
<identifier: Literal> =>
|
||||||
|
RSprocess::ConstantIdentifier{ identifier: identifier }
|
||||||
|
};
|
||||||
|
|
||||||
// ----- EnvironmentParser -----
|
// ----- EnvironmentParser -----
|
||||||
pub Environment: Box<RSenvironment<'input>> = {
|
pub Environment: Box<RSenvironment<'input>> = {
|
||||||
"[" "]" => Box::new(RSenvironment::new()),
|
"[" "]" => Box::new(RSenvironment::new()),
|
||||||
@ -68,7 +75,8 @@ pub Assert: Box<RSassert<'input>> = {
|
|||||||
|
|
||||||
Formula_Assert: RSassert<'input> = {
|
Formula_Assert: RSassert<'input> = {
|
||||||
"-" <f: Formula_Assert> => RSassert::Not(Box::new(f)),
|
"-" <f: Formula_Assert> => RSassert::Not(Box::new(f)),
|
||||||
"(" <f1: Formula_Assert> "^" <f2: Formula_Assert> ")" => RSassert::Xor(Box::new(f1), Box::new(f2)),
|
"(" <f1: Formula_Assert> "^" <f2: Formula_Assert> ")" =>
|
||||||
|
RSassert::Xor(Box::new(f1), Box::new(f2)),
|
||||||
"(" <f: Separeted<Formula_Assert, "\\/">> ")" => RSassert::Or(f),
|
"(" <f: Separeted<Formula_Assert, "\\/">> ")" => RSassert::Or(f),
|
||||||
"(" <f: Separeted<Formula_Assert, "/\\">> ")" => RSassert::And(f),
|
"(" <f: Separeted<Formula_Assert, "/\\">> ")" => RSassert::And(f),
|
||||||
<c: Set_of_entities> "inW" => RSassert::Sub(c, RSassertOp::InW),
|
<c: Set_of_entities> "inW" => RSassert::Sub(c, RSassertOp::InW),
|
||||||
@ -91,6 +99,8 @@ Formula_BHML: RSBHML<'input> = {
|
|||||||
"false" => RSBHML::False,
|
"false" => RSBHML::False,
|
||||||
"(" <g: Separeted<Formula_BHML, "\\/">> ")" => RSBHML::Or(g),
|
"(" <g: Separeted<Formula_BHML, "\\/">> ")" => RSBHML::Or(g),
|
||||||
"(" <g: Separeted<Formula_BHML, "/\\">> ")" => RSBHML::And(g),
|
"(" <g: Separeted<Formula_BHML, "/\\">> ")" => RSBHML::And(g),
|
||||||
"<" <f: Formula_Assert> ">" <g: Formula_BHML> => RSBHML::Diamond(Box::new(f), Box::new(g)),
|
"<" <f: Formula_Assert> ">" <g: Formula_BHML> =>
|
||||||
"[" <f: Formula_Assert> "]" <g: Formula_BHML> => RSBHML::Box(Box::new(f), Box::new(g)),
|
RSBHML::Diamond(Box::new(f), Box::new(g)),
|
||||||
|
"[" <f: Formula_Assert> "]" <g: Formula_BHML> =>
|
||||||
|
RSBHML::Box(Box::new(f), Box::new(g)),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,103 +1,2 @@
|
|||||||
use std::collections::BTreeMap;
|
pub mod structure;
|
||||||
|
pub mod classical;
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct RSset<'a> {
|
|
||||||
identifiers: Vec<&'a str>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, const N: usize> From<[&'a str; N]> for RSset<'a> {
|
|
||||||
fn from(mut arr: [&'a str; N]) -> Self {
|
|
||||||
arr.sort();
|
|
||||||
RSset{identifiers: arr.to_vec()}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&[&'a str]> for RSset<'a> {
|
|
||||||
fn from(arr: &[&'a str]) -> Self {
|
|
||||||
let mut tmp = arr.to_vec();
|
|
||||||
tmp.sort();
|
|
||||||
RSset{identifiers: tmp}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<Vec<&'a str>> for RSset<'a> {
|
|
||||||
fn from(mut arr: Vec<&'a str>) -> Self {
|
|
||||||
arr.sort();
|
|
||||||
RSset{identifiers: arr}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub enum RSprocess<'a> {
|
|
||||||
Nill,
|
|
||||||
ConstantIdentifier{identifier: &'a str},
|
|
||||||
EntitySet{entities: RSset<'a>, next_process: Box<RSprocess<'a>>},
|
|
||||||
WaitEntity{repeat: i64, repeated_process: Box<RSprocess<'a>>, next_process: Box<RSprocess<'a>>},
|
|
||||||
NondeterministicChoice{children: Vec<RSprocess<'a>>},
|
|
||||||
Summation{children: Vec<RSprocess<'a>>}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct RSenvironment<'a> {
|
|
||||||
definitions: BTreeMap<&'a str, Box<RSprocess<'a>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> RSenvironment<'a> {
|
|
||||||
pub fn new() -> RSenvironment<'a> {
|
|
||||||
RSenvironment{definitions: BTreeMap::new()}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, const N: usize> From<[(&'a str, Box<RSprocess<'a>>); N]> for RSenvironment<'a> {
|
|
||||||
fn from(arr: [(&'a str, Box<RSprocess<'a>>); N]) -> Self {
|
|
||||||
RSenvironment{definitions: BTreeMap::from(arr)}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&[(&'a str, Box<RSprocess<'a>>)]> for RSenvironment<'a> {
|
|
||||||
fn from(arr: &[(&'a str, Box<RSprocess<'a>>)]) -> Self {
|
|
||||||
RSenvironment{definitions: BTreeMap::from_iter(arr.to_vec())}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<Vec<(&'a str, Box<RSprocess<'a>>)>> for RSenvironment<'a> {
|
|
||||||
fn from(arr: Vec<(&'a str, Box<RSprocess<'a>>)>) -> Self {
|
|
||||||
RSenvironment{definitions: BTreeMap::from_iter(arr)}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub enum RSassertOp {
|
|
||||||
InW,
|
|
||||||
InR,
|
|
||||||
InI,
|
|
||||||
InP
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub enum RSassert<'a> {
|
|
||||||
Not(Box<RSassert<'a>>),
|
|
||||||
Xor(Box<RSassert<'a>>, Box<RSassert<'a>>),
|
|
||||||
Or(Vec<RSassert<'a>>),
|
|
||||||
And(Vec<RSassert<'a>>),
|
|
||||||
Sub(RSset<'a>, RSassertOp),
|
|
||||||
NonEmpty(RSassertOp)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub enum RSBHML<'a> {
|
|
||||||
True,
|
|
||||||
False,
|
|
||||||
Or(Vec<RSBHML<'a>>),
|
|
||||||
And(Vec<RSBHML<'a>>),
|
|
||||||
Diamond(Box<RSassert<'a>>, Box<RSBHML<'a>>),
|
|
||||||
Box(Box<RSassert<'a>>, Box<RSBHML<'a>>)
|
|
||||||
}
|
|
||||||
|
|||||||
174
src/rsprocess/structure.rs
Normal file
174
src/rsprocess/structure.rs
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
use std::collections::{BTreeMap, HashSet};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// RSset
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct RSset<'a> {
|
||||||
|
identifiers: HashSet<&'a str>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, const N: usize> From<[&'a str; N]> for RSset<'a> {
|
||||||
|
fn from(arr: [&'a str; N]) -> Self {
|
||||||
|
RSset{identifiers: HashSet::from(arr)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&[&'a str]> for RSset<'a> {
|
||||||
|
fn from(arr: &[&'a str]) -> Self {
|
||||||
|
RSset{identifiers: HashSet::from_iter(arr.to_vec())}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Vec<&'a str>> for RSset<'a> {
|
||||||
|
fn from(arr: Vec<&'a str>) -> Self {
|
||||||
|
RSset{identifiers: HashSet::from_iter(arr)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RSset<'a> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
RSset{identifiers: HashSet::new()}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_subset(&self, b: &RSset<'a>) -> bool {
|
||||||
|
self.identifiers.is_subset(&b.identifiers)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_disjoint(&self, b: &RSset<'a>) -> bool {
|
||||||
|
self.identifiers.is_disjoint(&b.identifiers)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn union(&self, b: &RSset<'a>) -> RSset<'a> {
|
||||||
|
// TODO maybe find more efficient way
|
||||||
|
let mut ret: RSset = b.clone();
|
||||||
|
ret.identifiers.extend(self.identifiers.iter());
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// RSreaction
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct RSreaction<'a> {
|
||||||
|
reactants: RSset<'a>,
|
||||||
|
inihibitors: RSset<'a>,
|
||||||
|
products: RSset<'a>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RSreaction<'a> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
RSreaction{ reactants: RSset::new(),
|
||||||
|
inihibitors: RSset::new(),
|
||||||
|
products: RSset::new(), }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from(reactants: RSset<'a>, inihibitors: RSset<'a>, products: RSset<'a>) -> Self {
|
||||||
|
RSreaction{ reactants,
|
||||||
|
inihibitors,
|
||||||
|
products }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enabled(&self, current_state: &RSset<'a>) -> bool {
|
||||||
|
self.reactants.is_subset(current_state)
|
||||||
|
&& self.inihibitors.is_disjoint(current_state)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn products_clone(&self) -> RSset<'a> {
|
||||||
|
self.products.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// RSprocess
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum RSprocess<'a> {
|
||||||
|
Nill,
|
||||||
|
ConstantIdentifier{identifier: &'a str},
|
||||||
|
EntitySet{entities: RSset<'a>, next_process: Box<RSprocess<'a>>},
|
||||||
|
WaitEntity{repeat: i64, repeated_process: Box<RSprocess<'a>>, next_process: Box<RSprocess<'a>>},
|
||||||
|
NondeterministicChoice{children: Vec<RSprocess<'a>>},
|
||||||
|
Summation{children: Vec<RSprocess<'a>>}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// RSenvironment
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct RSenvironment<'a> {
|
||||||
|
definitions: BTreeMap<&'a str, Box<RSprocess<'a>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RSenvironment<'a> {
|
||||||
|
pub fn new() -> RSenvironment<'a> {
|
||||||
|
RSenvironment{definitions: BTreeMap::new()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, const N: usize> From<[(&'a str, Box<RSprocess<'a>>); N]> for RSenvironment<'a> {
|
||||||
|
fn from(arr: [(&'a str, Box<RSprocess<'a>>); N]) -> Self {
|
||||||
|
RSenvironment{definitions: BTreeMap::from(arr)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&[(&'a str, Box<RSprocess<'a>>)]> for RSenvironment<'a> {
|
||||||
|
fn from(arr: &[(&'a str, Box<RSprocess<'a>>)]) -> Self {
|
||||||
|
RSenvironment{definitions: BTreeMap::from_iter(arr.to_vec())}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Vec<(&'a str, Box<RSprocess<'a>>)>> for RSenvironment<'a> {
|
||||||
|
fn from(arr: Vec<(&'a str, Box<RSprocess<'a>>)>) -> Self {
|
||||||
|
RSenvironment{definitions: BTreeMap::from_iter(arr)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// RSassertOp
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum RSassertOp {
|
||||||
|
InW,
|
||||||
|
InR,
|
||||||
|
InI,
|
||||||
|
InP
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// RSassert
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum RSassert<'a> {
|
||||||
|
Not(Box<RSassert<'a>>),
|
||||||
|
Xor(Box<RSassert<'a>>, Box<RSassert<'a>>),
|
||||||
|
Or(Vec<RSassert<'a>>),
|
||||||
|
And(Vec<RSassert<'a>>),
|
||||||
|
Sub(RSset<'a>, RSassertOp),
|
||||||
|
NonEmpty(RSassertOp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// RSBHML
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum RSBHML<'a> {
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
Or(Vec<RSBHML<'a>>),
|
||||||
|
And(Vec<RSBHML<'a>>),
|
||||||
|
Diamond(Box<RSassert<'a>>, Box<RSBHML<'a>>),
|
||||||
|
Box(Box<RSassert<'a>>, Box<RSBHML<'a>>)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user