Add functions for each Value case (#9736)

# Description
This PR ensures functions exist to extract and create each and every
`Value` case. It also renames `Value::boolean` to `Value::bool` to match
`Value::test_bool`, `Value::as_bool`, and `Value::Bool`. Similarly,
`Value::as_integer` was renamed to `Value::as_int` to be consistent with
`Value::int`, `Value::test_int`, and `Value::Int`. These two renames can
be undone if necessary.

# User-Facing Changes
No user facing changes, but two public functions were renamed which may
affect downstream dependents.
This commit is contained in:
Ian Manske
2023-07-21 13:20:33 +00:00
committed by GitHub
parent 0b1e368cea
commit 7e1b922ea7
30 changed files with 413 additions and 216 deletions

View File

@ -269,13 +269,13 @@ impl Value {
} else {
invalid!(Some(*$span), "should be a bool");
// Reconstruct
$vals[$index] = Value::boolean(config.$setting, *$span);
$vals[$index] = Value::bool(config.$setting, *$span);
}
};
}
macro_rules! try_int {
($cols:ident, $vals:ident, $index:ident, $span:expr, $setting:ident) => {
if let Ok(b) = &$vals[$index].as_integer() {
if let Ok(b) = &$vals[$index].as_int() {
config.$setting = *b;
} else {
invalid!(Some(*$span), "should be an int");
@ -350,8 +350,8 @@ impl Value {
vals[index] = Value::record(
vec!["use_ls_colors".into(), "clickable_links".into()],
vec![
Value::boolean(config.use_ls_colors, *span),
Value::boolean(config.show_clickable_links_in_ls, *span),
Value::bool(config.use_ls_colors, *span),
Value::bool(config.show_clickable_links_in_ls, *span),
],
*span,
);
@ -383,8 +383,8 @@ impl Value {
vals[index] = Value::record(
vec!["use_ls_colors".into(), "clickable_links".into()],
vec![
Value::boolean(config.use_ls_colors, *span),
Value::boolean(config.show_clickable_links_in_ls, *span),
Value::bool(config.use_ls_colors, *span),
Value::bool(config.show_clickable_links_in_ls, *span),
],
*span,
);
@ -415,7 +415,7 @@ impl Value {
// Reconstruct
vals[index] = Value::record(
vec!["always_trash".into()],
vec![Value::boolean(config.rm_always_trash, *span)],
vec![Value::bool(config.rm_always_trash, *span)],
*span,
);
}
@ -495,10 +495,10 @@ impl Value {
"isolation".into(),
],
vec![
Value::boolean(config.sync_history_on_enter, *span),
Value::bool(config.sync_history_on_enter, *span),
Value::int(config.max_history_size, *span),
reconstruct_history_file_format!(span),
Value::boolean(config.history_isolation, *span),
Value::bool(config.history_isolation, *span),
],
*span,
);
@ -524,7 +524,7 @@ impl Value {
vec![
Value::int(config.max_external_completion_results, *$span),
reconstruct_external_completer!($span),
Value::boolean(config.enable_external_completion, *$span),
Value::bool(config.enable_external_completion, *$span),
],
*$span,
)
@ -662,10 +662,10 @@ impl Value {
"external".into(),
],
vec![
Value::boolean(config.quick_completions, *span),
Value::boolean(config.partial_completions, *span),
Value::bool(config.quick_completions, *span),
Value::bool(config.partial_completions, *span),
Value::string(config.completion_algorithm.clone(), *span),
Value::boolean(config.case_sensitive_completions, *span),
Value::bool(config.case_sensitive_completions, *span),
reconstruct_external!(span),
],
*span,
@ -884,7 +884,7 @@ impl Value {
],
vec![
Value::string("wrapping", *$span),
Value::boolean(*try_to_keep_words, *$span),
Value::bool(*try_to_keep_words, *$span),
],
*$span,
),
@ -982,7 +982,7 @@ impl Value {
Value::string(config.table_mode.clone(), *span),
reconstruct_index_mode!(span),
reconstruct_trim_strategy!(span),
Value::boolean(config.table_show_empty, *span),
Value::bool(config.table_show_empty, *span),
],
*span,
)
@ -1026,7 +1026,7 @@ impl Value {
vals[index] = Value::record(
vec!["metric".into(), "format".into()],
vec![
Value::boolean(config.filesize_metric, *span),
Value::bool(config.filesize_metric, *span),
Value::string(config.filesize_format.clone(), *span),
],
*span,
@ -1270,7 +1270,7 @@ impl Value {
vals[index] = Value::record(
vec!["metric".into(), "format".into()],
vec![
Value::boolean(config.filesize_metric, *span),
Value::bool(config.filesize_metric, *span),
Value::string(config.filesize_format.clone(), *span),
],
*span,

View File

@ -125,7 +125,7 @@ pub enum Value {
impl Clone for Value {
fn clone(&self) -> Self {
match self {
Value::Bool { val, span } => Value::boolean(*val, *span),
Value::Bool { val, span } => Value::bool(*val, *span),
Value::Int { val, span } => Value::int(*val, *span),
Value::Filesize { val, span } => Value::Filesize {
val: *val,
@ -193,20 +193,84 @@ impl Clone for Value {
}
impl Value {
pub fn as_char(&self) -> Result<char, ShellError> {
pub fn as_bool(&self) -> Result<bool, ShellError> {
match self {
Value::String { val, span } => {
let mut chars = val.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => Ok(c),
_ => Err(ShellError::MissingParameter {
param_name: "single character separator".into(),
span: *span,
}),
}
}
Value::Bool { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert {
to_type: "char".into(),
to_type: "boolean".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_int(&self) -> Result<i64, ShellError> {
match self {
Value::Int { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert {
to_type: "integer".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_float(&self) -> Result<f64, ShellError> {
match self {
Value::Float { val, .. } => Ok(*val),
Value::Int { val, .. } => Ok(*val as f64),
x => Err(ShellError::CantConvert {
to_type: "float".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_filesize(&self) -> Result<i64, ShellError> {
match self {
Value::Filesize { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert {
to_type: "filesize".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_duration(&self) -> Result<i64, ShellError> {
match self {
Value::Duration { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert {
to_type: "duration".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_date(&self) -> Result<DateTime<FixedOffset>, ShellError> {
match self {
Value::Date { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert {
to_type: "date".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_range(&self) -> Result<&Range, ShellError> {
match self {
Value::Range { val, .. } => Ok(val.as_ref()),
x => Err(ShellError::CantConvert {
to_type: "range".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
@ -270,6 +334,27 @@ impl Value {
}
}
pub fn as_char(&self) -> Result<char, ShellError> {
match self {
Value::String { val, span } => {
let mut chars = val.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => Ok(c),
_ => Err(ShellError::MissingParameter {
param_name: "single character separator".into(),
span: *span,
}),
}
}
x => Err(ShellError::CantConvert {
to_type: "char".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_path(&self) -> Result<PathBuf, ShellError> {
match self {
Value::String { val, .. } => Ok(PathBuf::from(val)),
@ -282,32 +367,6 @@ impl Value {
}
}
pub fn as_block(&self) -> Result<BlockId, ShellError> {
match self {
Value::Block { val, .. } => Ok(*val),
Value::Closure { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert {
to_type: "block".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_binary(&self) -> Result<&[u8], ShellError> {
match self {
Value::Binary { val, .. } => Ok(val),
Value::String { val, .. } => Ok(val.as_bytes()),
x => Err(ShellError::CantConvert {
to_type: "binary".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_record(&self) -> Result<(&[String], &[Value]), ShellError> {
match self {
Value::Record { cols, vals, .. } => Ok((cols, vals)),
@ -332,11 +391,12 @@ impl Value {
}
}
pub fn as_bool(&self) -> Result<bool, ShellError> {
pub fn as_block(&self) -> Result<BlockId, ShellError> {
match self {
Value::Bool { val, .. } => Ok(*val),
Value::Block { val, .. } => Ok(*val),
Value::Closure { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert {
to_type: "boolean".into(),
to_type: "block".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
@ -344,12 +404,11 @@ impl Value {
}
}
pub fn as_float(&self) -> Result<f64, ShellError> {
pub fn as_closure(&self) -> Result<(BlockId, &HashMap<VarId, Value>), ShellError> {
match self {
Value::Float { val, .. } => Ok(*val),
Value::Int { val, .. } => Ok(*val as f64),
Value::Closure { val, captures, .. } => Ok((*val, captures)),
x => Err(ShellError::CantConvert {
to_type: "float".into(),
to_type: "closure".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
@ -357,11 +416,60 @@ impl Value {
}
}
pub fn as_integer(&self) -> Result<i64, ShellError> {
pub fn as_binary(&self) -> Result<&[u8], ShellError> {
match self {
Value::Int { val, .. } => Ok(*val),
Value::Binary { val, .. } => Ok(val),
Value::String { val, .. } => Ok(val.as_bytes()),
x => Err(ShellError::CantConvert {
to_type: "integer".into(),
to_type: "binary".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_cell_path(&self) -> Result<&CellPath, ShellError> {
match self {
Value::CellPath { val, .. } => Ok(val),
x => Err(ShellError::CantConvert {
to_type: "cell path".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_custom_value(&self) -> Result<&dyn CustomValue, ShellError> {
match self {
Value::CustomValue { val, .. } => Ok(val.as_ref()),
x => Err(ShellError::CantConvert {
to_type: "custom value".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_lazy_record(&self) -> Result<&dyn for<'a> LazyRecord<'a>, ShellError> {
match self {
Value::LazyRecord { val, .. } => Ok(val.as_ref()),
x => Err(ShellError::CantConvert {
to_type: "lazy record".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
}),
}
}
pub fn as_match_pattern(&self) -> Result<&MatchPattern, ShellError> {
match self {
Value::MatchPattern { val, .. } => Ok(val.as_ref()),
x => Err(ShellError::CantConvert {
to_type: "match pattern".into(),
from_type: x.get_type().to_string(),
span: self.span()?,
help: None,
@ -768,11 +876,6 @@ impl Value {
matches!(self, Value::Nothing { .. })
}
/// Create a new `Nothing` value
pub fn nothing(span: Span) -> Value {
Value::Nothing { span }
}
/// Follow a given cell path into the value: for example accessing select elements in a stream or list
pub fn follow_cell_path(
self,
@ -1635,18 +1738,8 @@ impl Value {
}
}
pub fn string(val: impl Into<String>, span: Span) -> Value {
Value::String {
val: val.into(),
span,
}
}
pub fn binary(val: impl Into<Vec<u8>>, span: Span) -> Value {
Value::Binary {
val: val.into(),
span,
}
pub fn bool(val: bool, span: Span) -> Value {
Value::Bool { val, span }
}
pub fn int(val: i64, span: Span) -> Value {
@ -1657,8 +1750,30 @@ impl Value {
Value::Float { val, span }
}
pub fn boolean(val: bool, span: Span) -> Value {
Value::Bool { val, span }
pub fn filesize(val: i64, span: Span) -> Value {
Value::Filesize { val, span }
}
pub fn duration(val: i64, span: Span) -> Value {
Value::Duration { val, span }
}
pub fn date(val: DateTime<FixedOffset>, span: Span) -> Value {
Value::Date { val, span }
}
pub fn range(val: Range, span: Span) -> Value {
Value::Range {
val: Box::new(val),
span,
}
}
pub fn string(val: impl Into<String>, span: Span) -> Value {
Value::String {
val: val.into(),
span,
}
}
pub fn record(cols: Vec<String>, vals: Vec<Value>, span: Span) -> Value {
@ -1679,83 +1794,165 @@ impl Value {
Value::List { vals, span }
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_string(s: impl Into<String>) -> Value {
Value::string(s, Span::test_data())
pub fn block(val: BlockId, span: Span) -> Value {
Value::Block { val, span }
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_int(val: i64) -> Value {
Value::Int {
pub fn closure(val: BlockId, captures: HashMap<VarId, Value>, span: Span) -> Value {
Value::Closure {
val,
span: Span::test_data(),
captures,
span,
}
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_float(val: f64) -> Value {
Value::Float {
val,
span: Span::test_data(),
/// Create a new `Nothing` value
pub fn nothing(span: Span) -> Value {
Value::Nothing { span }
}
pub fn error(error: ShellError) -> Value {
Value::Error {
error: Box::new(error),
}
}
pub fn binary(val: impl Into<Vec<u8>>, span: Span) -> Value {
Value::Binary {
val: val.into(),
span,
}
}
pub fn cell_path(val: CellPath, span: Span) -> Value {
Value::CellPath { val, span }
}
pub fn custom_value(val: Box<dyn CustomValue>, span: Span) -> Value {
Value::CustomValue { val, span }
}
pub fn lazy_record(val: Box<dyn for<'a> LazyRecord<'a>>, span: Span) -> Value {
Value::LazyRecord { val, span }
}
pub fn match_pattern(val: MatchPattern, span: Span) -> Value {
Value::MatchPattern {
val: Box::new(val),
span,
}
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_bool(val: bool) -> Value {
Value::Bool {
val,
span: Span::test_data(),
}
Value::bool(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_int(val: i64) -> Value {
Value::int(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_float(val: f64) -> Value {
Value::float(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_filesize(val: i64) -> Value {
Value::Filesize {
val,
span: Span::test_data(),
}
Value::filesize(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_nothing() -> Value {
Value::Nothing {
span: Span::test_data(),
}
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_record(cols: Vec<impl Into<String>>, vals: Vec<Value>) -> Value {
Value::Record {
cols: cols.into_iter().map(|s| s.into()).collect(),
vals,
span: Span::test_data(),
}
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_list(vals: Vec<Value>) -> Value {
Value::List {
vals,
span: Span::test_data(),
}
pub fn test_duration(val: i64) -> Value {
Value::duration(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_date(val: DateTime<FixedOffset>) -> Value {
Value::Date {
val,
span: Span::test_data(),
}
Value::date(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_range(val: Range) -> Value {
Value::range(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_string(val: impl Into<String>) -> Value {
Value::string(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_record(cols: Vec<impl Into<String>>, vals: Vec<Value>) -> Value {
Value::record(
cols.into_iter().map(|s| s.into()).collect(),
vals,
Span::test_data(),
)
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_list(vals: Vec<Value>) -> Value {
Value::list(vals, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_block(val: BlockId) -> Value {
Value::block(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_closure(val: BlockId, captures: HashMap<VarId, Value>) -> Value {
Value::closure(val, captures, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_nothing() -> Value {
Value::nothing(Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_binary(val: impl Into<Vec<u8>>) -> Value {
Value::binary(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_cell_path(val: CellPath) -> Value {
Value::cell_path(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_custom_value(val: Box<dyn CustomValue>) -> Value {
Value::custom_value(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_lazy_record(val: Box<dyn for<'a> LazyRecord<'a>>) -> Value {
Value::lazy_record(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_match_pattern(val: MatchPattern) -> Value {
Value::match_pattern(val, Span::test_data())
}
}
@ -3892,7 +4089,7 @@ mod tests {
vals: vec![
Value::int(0, Span::unknown()),
Value::float(0.0, Span::unknown()),
Value::boolean(false, Span::unknown()),
Value::bool(false, Span::unknown()),
],
span: Span::unknown(),
};

View File

@ -105,11 +105,11 @@ impl Range {
}
pub fn from(&self) -> Result<i64, ShellError> {
self.from.as_integer()
self.from.as_int()
}
pub fn to(&self) -> Result<i64, ShellError> {
let to = self.to.as_integer()?;
let to = self.to.as_int()?;
if self.is_end_inclusive() {
Ok(to)
} else {