forked from extern/nushell
Fix up calls and pipelines
This commit is contained in:
parent
7c8504ea24
commit
df63490266
@ -34,7 +34,7 @@ impl Command for Benchmark {
|
|||||||
|
|
||||||
let state = context.enter_scope();
|
let state = context.enter_scope();
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
eval_block(&state, block)?;
|
eval_block(&state, block, Value::nothing())?;
|
||||||
let end_time = Instant::now();
|
let end_time = Instant::now();
|
||||||
println!("{} ms", (end_time - start_time).as_millis());
|
println!("{} ms", (end_time - start_time).as_millis());
|
||||||
Ok(Value::Nothing {
|
Ok(Value::Nothing {
|
||||||
|
@ -5,7 +5,7 @@ use nu_protocol::{
|
|||||||
Signature, SyntaxShape,
|
Signature, SyntaxShape,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Alias, Benchmark, BuildString, Def, For, If, Let, LetEnv};
|
use crate::{Alias, Benchmark, BuildString, Def, For, If, Length, Let, LetEnv};
|
||||||
|
|
||||||
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
|
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
|
||||||
let engine_state = Rc::new(RefCell::new(EngineState::new()));
|
let engine_state = Rc::new(RefCell::new(EngineState::new()));
|
||||||
@ -33,6 +33,8 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
|
|||||||
|
|
||||||
working_set.add_decl(Box::new(Benchmark));
|
working_set.add_decl(Box::new(Benchmark));
|
||||||
|
|
||||||
|
working_set.add_decl(Box::new(Length));
|
||||||
|
|
||||||
let sig = Signature::build("exit");
|
let sig = Signature::build("exit");
|
||||||
working_set.add_decl(sig.predeclare());
|
working_set.add_decl(sig.predeclare());
|
||||||
let sig = Signature::build("vars");
|
let sig = Signature::build("vars");
|
||||||
|
@ -33,7 +33,7 @@ impl Command for For {
|
|||||||
&self,
|
&self,
|
||||||
context: &EvaluationContext,
|
context: &EvaluationContext,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: Value,
|
input: Value,
|
||||||
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
|
||||||
let var_id = call.positional[0]
|
let var_id = call.positional[0]
|
||||||
.as_var()
|
.as_var()
|
||||||
@ -62,7 +62,7 @@ impl Command for For {
|
|||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
state.add_var(var_id, x.clone());
|
state.add_var(var_id, x.clone());
|
||||||
eval_block(&state, block)?;
|
eval_block(&state, block, input.clone())?;
|
||||||
}
|
}
|
||||||
if let Value::Int { ref mut val, .. } = x {
|
if let Value::Int { ref mut val, .. } = x {
|
||||||
*val += 1
|
*val += 1
|
||||||
|
@ -29,7 +29,7 @@ impl Command for If {
|
|||||||
&self,
|
&self,
|
||||||
context: &EvaluationContext,
|
context: &EvaluationContext,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: Value,
|
input: Value,
|
||||||
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
|
||||||
let cond = &call.positional[0];
|
let cond = &call.positional[0];
|
||||||
let then_block = call.positional[1]
|
let then_block = call.positional[1]
|
||||||
@ -44,13 +44,13 @@ impl Command for If {
|
|||||||
if val {
|
if val {
|
||||||
let block = engine_state.get_block(then_block);
|
let block = engine_state.get_block(then_block);
|
||||||
let state = context.enter_scope();
|
let state = context.enter_scope();
|
||||||
eval_block(&state, block)
|
eval_block(&state, block, input)
|
||||||
} else if let Some(else_case) = else_case {
|
} else if let Some(else_case) = else_case {
|
||||||
if let Some(else_expr) = else_case.as_keyword() {
|
if let Some(else_expr) = else_case.as_keyword() {
|
||||||
if let Some(block_id) = else_expr.as_block() {
|
if let Some(block_id) = else_expr.as_block() {
|
||||||
let block = engine_state.get_block(block_id);
|
let block = engine_state.get_block(block_id);
|
||||||
let state = context.enter_scope();
|
let state = context.enter_scope();
|
||||||
eval_block(&state, block)
|
eval_block(&state, block, input)
|
||||||
} else {
|
} else {
|
||||||
eval_expression(context, else_expr)
|
eval_expression(context, else_expr)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EvaluationContext};
|
||||||
|
use nu_protocol::{Signature, Value};
|
||||||
|
|
||||||
|
pub struct Length;
|
||||||
|
|
||||||
|
impl Command for Length {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"length"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Count the number of elements in the input."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build("length")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
_context: &EvaluationContext,
|
||||||
|
call: &Call,
|
||||||
|
input: Value,
|
||||||
|
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
|
||||||
|
match input {
|
||||||
|
Value::List { val, .. } => {
|
||||||
|
let length = val.count();
|
||||||
|
|
||||||
|
Ok(Value::Int {
|
||||||
|
val: length as i64,
|
||||||
|
span: call.head,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Value::Table { val, .. } => {
|
||||||
|
let length = val.count();
|
||||||
|
|
||||||
|
Ok(Value::Int {
|
||||||
|
val: length as i64,
|
||||||
|
span: call.head,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => Ok(Value::Int {
|
||||||
|
val: 1,
|
||||||
|
span: call.head,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ mod def;
|
|||||||
mod default_context;
|
mod default_context;
|
||||||
mod for_;
|
mod for_;
|
||||||
mod if_;
|
mod if_;
|
||||||
|
mod length;
|
||||||
mod let_;
|
mod let_;
|
||||||
mod let_env;
|
mod let_env;
|
||||||
|
|
||||||
@ -15,5 +16,6 @@ pub use def::Def;
|
|||||||
pub use default_context::create_default_context;
|
pub use default_context::create_default_context;
|
||||||
pub use for_::For;
|
pub use for_::For;
|
||||||
pub use if_::If;
|
pub use if_::If;
|
||||||
|
pub use length::Length;
|
||||||
pub use let_::Let;
|
pub use let_::Let;
|
||||||
pub use let_env::LetEnv;
|
pub use let_env::LetEnv;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use nu_protocol::ast::{Block, Call, Expr, Expression, Operator, Statement};
|
use nu_protocol::ast::{Block, Call, Expr, Expression, Operator, Statement};
|
||||||
use nu_protocol::engine::EvaluationContext;
|
use nu_protocol::engine::EvaluationContext;
|
||||||
use nu_protocol::{IntoRowStream, IntoValueStream, ShellError, Span, Value};
|
use nu_protocol::{IntoRowStream, IntoValueStream, ShellError, Value};
|
||||||
|
|
||||||
pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> {
|
pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> {
|
||||||
match op {
|
match op {
|
||||||
@ -12,7 +12,7 @@ pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_call(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
|
fn eval_call(context: &EvaluationContext, call: &Call, input: Value) -> Result<Value, ShellError> {
|
||||||
let engine_state = context.engine_state.borrow();
|
let engine_state = context.engine_state.borrow();
|
||||||
let decl = engine_state.get_decl(call.decl_id);
|
let decl = engine_state.get_decl(call.decl_id);
|
||||||
if let Some(block_id) = decl.get_custom_command() {
|
if let Some(block_id) = decl.get_custom_command() {
|
||||||
@ -32,15 +32,9 @@ fn eval_call(context: &EvaluationContext, call: &Call) -> Result<Value, ShellErr
|
|||||||
}
|
}
|
||||||
let engine_state = state.engine_state.borrow();
|
let engine_state = state.engine_state.borrow();
|
||||||
let block = engine_state.get_block(block_id);
|
let block = engine_state.get_block(block_id);
|
||||||
eval_block(&state, block)
|
eval_block(&state, block, input)
|
||||||
} else {
|
} else {
|
||||||
decl.run(
|
decl.run(context, call, input)
|
||||||
context,
|
|
||||||
call,
|
|
||||||
Value::Nothing {
|
|
||||||
span: Span::unknown(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +58,7 @@ pub fn eval_expression(
|
|||||||
Expr::Var(var_id) => context
|
Expr::Var(var_id) => context
|
||||||
.get_var(*var_id)
|
.get_var(*var_id)
|
||||||
.map_err(move |_| ShellError::VariableNotFound(expr.span)),
|
.map_err(move |_| ShellError::VariableNotFound(expr.span)),
|
||||||
Expr::Call(call) => eval_call(context, call),
|
Expr::Call(_) => panic!("Internal error: calls should be handled by eval_block"),
|
||||||
Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)),
|
Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)),
|
||||||
Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }),
|
Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }),
|
||||||
Expr::BinaryOp(lhs, op, rhs) => {
|
Expr::BinaryOp(lhs, op, rhs) => {
|
||||||
@ -93,7 +87,7 @@ pub fn eval_expression(
|
|||||||
let block = engine_state.get_block(*block_id);
|
let block = engine_state.get_block(*block_id);
|
||||||
|
|
||||||
let state = context.enter_scope();
|
let state = context.enter_scope();
|
||||||
eval_block(&state, block)
|
eval_block(&state, block, Value::nothing())
|
||||||
}
|
}
|
||||||
Expr::Block(block_id) => Ok(Value::Block {
|
Expr::Block(block_id) => Ok(Value::Block {
|
||||||
val: *block_id,
|
val: *block_id,
|
||||||
@ -139,16 +133,29 @@ pub fn eval_expression(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_block(state: &EvaluationContext, block: &Block) -> Result<Value, ShellError> {
|
pub fn eval_block(
|
||||||
let mut last = Ok(Value::Nothing {
|
context: &EvaluationContext,
|
||||||
span: Span { start: 0, end: 0 },
|
block: &Block,
|
||||||
});
|
mut input: Value,
|
||||||
|
) -> Result<Value, ShellError> {
|
||||||
for stmt in &block.stmts {
|
for stmt in &block.stmts {
|
||||||
if let Statement::Expression(expression) = stmt {
|
if let Statement::Pipeline(pipeline) = stmt {
|
||||||
last = Ok(eval_expression(state, expression)?);
|
for elem in &pipeline.expressions {
|
||||||
|
match elem {
|
||||||
|
Expression {
|
||||||
|
expr: Expr::Call(call),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
input = eval_call(context, call, input)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
elem => {
|
||||||
|
input = eval_expression(context, elem)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
last
|
Ok(input)
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ pub fn flatten_statement(
|
|||||||
stmt: &Statement,
|
stmt: &Statement,
|
||||||
) -> Vec<(Span, FlatShape)> {
|
) -> Vec<(Span, FlatShape)> {
|
||||||
match stmt {
|
match stmt {
|
||||||
Statement::Expression(expr) => flatten_expression(working_set, expr),
|
|
||||||
Statement::Pipeline(pipeline) => flatten_pipeline(working_set, pipeline),
|
Statement::Pipeline(pipeline) => flatten_pipeline(working_set, pipeline),
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
|
@ -2066,30 +2066,30 @@ pub fn parse_def(
|
|||||||
});
|
});
|
||||||
|
|
||||||
(
|
(
|
||||||
Statement::Expression(Expression {
|
Statement::Pipeline(Pipeline::from_vec(vec![Expression {
|
||||||
expr: Expr::Call(call),
|
expr: Expr::Call(call),
|
||||||
span: span(spans),
|
span: span(spans),
|
||||||
ty: Type::Unknown,
|
ty: Type::Unknown,
|
||||||
}),
|
}])),
|
||||||
error,
|
error,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => (
|
_ => (
|
||||||
Statement::Expression(Expression {
|
Statement::Pipeline(Pipeline::from_vec(vec![Expression {
|
||||||
expr: Expr::Garbage,
|
expr: Expr::Garbage,
|
||||||
span: span(spans),
|
span: span(spans),
|
||||||
ty: Type::Unknown,
|
ty: Type::Unknown,
|
||||||
}),
|
}])),
|
||||||
error,
|
error,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
Statement::Expression(Expression {
|
Statement::Pipeline(Pipeline::from_vec(vec![Expression {
|
||||||
expr: Expr::Garbage,
|
expr: Expr::Garbage,
|
||||||
span: span(spans),
|
span: span(spans),
|
||||||
ty: Type::Unknown,
|
ty: Type::Unknown,
|
||||||
}),
|
}])),
|
||||||
Some(ParseError::UnknownState(
|
Some(ParseError::UnknownState(
|
||||||
"internal error: definition unparseable".into(),
|
"internal error: definition unparseable".into(),
|
||||||
span(spans),
|
span(spans),
|
||||||
@ -2130,22 +2130,22 @@ pub fn parse_alias(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
Statement::Expression(Expression {
|
Statement::Pipeline(Pipeline::from_vec(vec![Expression {
|
||||||
expr: Expr::Call(call),
|
expr: Expr::Call(call),
|
||||||
span: call_span,
|
span: call_span,
|
||||||
ty: Type::Unknown,
|
ty: Type::Unknown,
|
||||||
}),
|
}])),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
Statement::Expression(Expression {
|
Statement::Pipeline(Pipeline::from_vec(vec![Expression {
|
||||||
expr: Expr::Garbage,
|
expr: Expr::Garbage,
|
||||||
span: span(spans),
|
span: span(spans),
|
||||||
ty: Type::Unknown,
|
ty: Type::Unknown,
|
||||||
}),
|
}])),
|
||||||
Some(ParseError::UnknownState(
|
Some(ParseError::UnknownState(
|
||||||
"internal error: let statement unparseable".into(),
|
"internal error: let statement unparseable".into(),
|
||||||
span(spans),
|
span(spans),
|
||||||
@ -2175,21 +2175,21 @@ pub fn parse_let(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
Statement::Expression(Expression {
|
Statement::Pipeline(Pipeline::from_vec(vec![Expression {
|
||||||
expr: Expr::Call(call),
|
expr: Expr::Call(call),
|
||||||
span: call_span,
|
span: call_span,
|
||||||
ty: Type::Unknown,
|
ty: Type::Unknown,
|
||||||
}),
|
}])),
|
||||||
err,
|
err,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
Statement::Expression(Expression {
|
Statement::Pipeline(Pipeline::from_vec(vec![Expression {
|
||||||
expr: Expr::Garbage,
|
expr: Expr::Garbage,
|
||||||
span: span(spans),
|
span: span(spans),
|
||||||
ty: Type::Unknown,
|
ty: Type::Unknown,
|
||||||
}),
|
}])),
|
||||||
Some(ParseError::UnknownState(
|
Some(ParseError::UnknownState(
|
||||||
"internal error: let statement unparseable".into(),
|
"internal error: let statement unparseable".into(),
|
||||||
span(spans),
|
span(spans),
|
||||||
@ -2210,7 +2210,7 @@ pub fn parse_statement(
|
|||||||
(stmt, None)
|
(stmt, None)
|
||||||
} else {
|
} else {
|
||||||
let (expr, err) = parse_expression(working_set, spans);
|
let (expr, err) = parse_expression(working_set, spans);
|
||||||
(Statement::Expression(expr), err)
|
(Statement::Pipeline(Pipeline::from_vec(vec![expr])), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use nu_parser::ParseError;
|
use nu_parser::ParseError;
|
||||||
use nu_parser::*;
|
use nu_parser::*;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Expr, Expression, Statement},
|
ast::{Expr, Expression, Pipeline, Statement},
|
||||||
engine::{EngineState, StateWorkingSet},
|
engine::{EngineState, StateWorkingSet},
|
||||||
Signature, SyntaxShape,
|
Signature, SyntaxShape,
|
||||||
};
|
};
|
||||||
@ -15,13 +15,21 @@ pub fn parse_int() {
|
|||||||
|
|
||||||
assert!(err.is_none());
|
assert!(err.is_none());
|
||||||
assert!(block.len() == 1);
|
assert!(block.len() == 1);
|
||||||
assert!(matches!(
|
match &block[0] {
|
||||||
block[0],
|
Statement::Pipeline(Pipeline {
|
||||||
Statement::Expression(Expression {
|
expressions: expressions,
|
||||||
expr: Expr::Int(3),
|
}) => {
|
||||||
..
|
assert!(expressions.len() == 1);
|
||||||
})
|
assert!(matches!(
|
||||||
));
|
expressions[0],
|
||||||
|
Expression {
|
||||||
|
expr: Expr::Int(3),
|
||||||
|
..
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => panic!("No match"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -38,11 +46,16 @@ pub fn parse_call() {
|
|||||||
assert!(block.len() == 1);
|
assert!(block.len() == 1);
|
||||||
|
|
||||||
match &block[0] {
|
match &block[0] {
|
||||||
Statement::Expression(Expression {
|
Statement::Pipeline(Pipeline { expressions }) => {
|
||||||
expr: Expr::Call(call),
|
assert_eq!(expressions.len(), 1);
|
||||||
..
|
|
||||||
}) => {
|
if let Expression {
|
||||||
assert_eq!(call.decl_id, 0);
|
expr: Expr::Call(call),
|
||||||
|
..
|
||||||
|
} = &expressions[0]
|
||||||
|
{
|
||||||
|
assert_eq!(call.decl_id, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("not a call"),
|
_ => panic!("not a call"),
|
||||||
}
|
}
|
||||||
|
@ -17,4 +17,8 @@ impl Pipeline {
|
|||||||
expressions: vec![],
|
expressions: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_vec(expressions: Vec<Expression>) -> Pipeline {
|
||||||
|
Self { expressions }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use super::{Expression, Pipeline};
|
use super::Pipeline;
|
||||||
use crate::DeclId;
|
use crate::DeclId;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Declaration(DeclId),
|
Declaration(DeclId),
|
||||||
Pipeline(Pipeline),
|
Pipeline(Pipeline),
|
||||||
Expression(Expression),
|
|
||||||
}
|
}
|
||||||
|
@ -197,6 +197,12 @@ impl Value {
|
|||||||
Value::Nothing { .. } => String::new(),
|
Value::Nothing { .. } => String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn nothing() -> Value {
|
||||||
|
Value::Nothing {
|
||||||
|
span: Span::unknown(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Value {
|
impl PartialEq for Value {
|
||||||
|
@ -2,7 +2,10 @@ use nu_cli::{report_parsing_error, report_shell_error, NuHighlighter};
|
|||||||
use nu_command::create_default_context;
|
use nu_command::create_default_context;
|
||||||
use nu_engine::eval_block;
|
use nu_engine::eval_block;
|
||||||
use nu_parser::parse_file;
|
use nu_parser::parse_file;
|
||||||
use nu_protocol::engine::{EngineState, EvaluationContext, StateWorkingSet};
|
use nu_protocol::{
|
||||||
|
engine::{EngineState, EvaluationContext, StateWorkingSet},
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@ -32,7 +35,7 @@ fn main() -> std::io::Result<()> {
|
|||||||
stack: nu_protocol::engine::Stack::new(),
|
stack: nu_protocol::engine::Stack::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match eval_block(&state, &block) {
|
match eval_block(&state, &block, Value::nothing()) {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
println!("{}", value.into_string());
|
println!("{}", value.into_string());
|
||||||
}
|
}
|
||||||
@ -106,7 +109,7 @@ fn main() -> std::io::Result<()> {
|
|||||||
stack: stack.clone(),
|
stack: stack.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match eval_block(&state, &block) {
|
match eval_block(&state, &block, Value::nothing()) {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
println!("{}", value.into_string());
|
println!("{}", value.into_string());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user