refact: Use Option instead of custom ValueTypeOrThunk
This loses the custom name for "thunk", but checking thunkness is a niche use case that I don't think we should spend much code on. (cherry picked from commit 7bdff525c13234ce6a32ea9346292d948b0840c1)
This commit is contained in:
parent
19361acb12
commit
22ffd20c53
2 changed files with 44 additions and 43 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::value::{Int, Value, ValueType, ValueTypeOrThunk};
|
use crate::value::{Int, Value, ValueType};
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
@ -133,20 +133,20 @@ impl EvalState {
|
||||||
}
|
}
|
||||||
self.context.check_err()
|
self.context.check_err()
|
||||||
}
|
}
|
||||||
pub fn value_type_unforced(&self, value: &Value) -> ValueTypeOrThunk {
|
pub fn value_type_unforced(&self, value: &Value) -> Option<ValueType> {
|
||||||
let r = unsafe { raw::get_type(self.context.ptr(), value.raw_ptr()) };
|
let r = unsafe { raw::get_type(self.context.ptr(), value.raw_ptr()) };
|
||||||
self.context.check_err().unwrap();
|
self.context.check_err().unwrap();
|
||||||
ValueTypeOrThunk::from_raw(r)
|
ValueType::from_raw(r)
|
||||||
}
|
}
|
||||||
pub fn value_type(&self, value: &Value) -> Result<ValueType> {
|
pub fn value_type(&self, value: &Value) -> Result<ValueType> {
|
||||||
match self.value_type_unforced(value) {
|
match self.value_type_unforced(value) {
|
||||||
ValueTypeOrThunk::ValueType(a) => Ok(a),
|
Some(a) => Ok(a),
|
||||||
ValueTypeOrThunk::Thunk => {
|
None => {
|
||||||
self.force(value)?;
|
self.force(value)?;
|
||||||
match self.value_type_unforced(value) {
|
match self.value_type_unforced(value) {
|
||||||
ValueTypeOrThunk::ValueType(a) => Ok(a),
|
Some(a) => Ok(a),
|
||||||
ValueTypeOrThunk::Thunk => {
|
None => {
|
||||||
panic!("values should not be thunks after having been forced.")
|
panic!("Nix value must not be thunk after being forced.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -488,9 +488,9 @@ mod tests {
|
||||||
let v2 = v.clone();
|
let v2 = v.clone();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::Int));
|
assert!(t == Some(ValueType::Int));
|
||||||
let t2 = es.value_type_unforced(&v2);
|
let t2 = es.value_type_unforced(&v2);
|
||||||
assert!(t2 == ValueTypeOrThunk::ValueType(ValueType::Int));
|
assert!(t2 == Some(ValueType::Int));
|
||||||
gc_now();
|
gc_now();
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -504,7 +504,7 @@ mod tests {
|
||||||
let v = es.eval_from_string("true", "<test>").unwrap();
|
let v = es.eval_from_string("true", "<test>").unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::Bool));
|
assert!(t == Some(ValueType::Bool));
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
@ -532,7 +532,7 @@ mod tests {
|
||||||
let v = es.eval_from_string("{ }", "<test>").unwrap();
|
let v = es.eval_from_string("{ }", "<test>").unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::AttrSet));
|
assert!(t == Some(ValueType::AttrSet));
|
||||||
let attrs = es.require_attrs_names(&v).unwrap();
|
let attrs = es.require_attrs_names(&v).unwrap();
|
||||||
assert_eq!(attrs.len(), 0);
|
assert_eq!(attrs.len(), 0);
|
||||||
})
|
})
|
||||||
|
|
@ -653,7 +653,7 @@ mod tests {
|
||||||
let v = es.eval_from_string("\"hello\"", "<test>").unwrap();
|
let v = es.eval_from_string("\"hello\"", "<test>").unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::String));
|
assert!(t == Some(ValueType::String));
|
||||||
let s = es.require_string(&v).unwrap();
|
let s = es.require_string(&v).unwrap();
|
||||||
assert!(s == "hello");
|
assert!(s == "hello");
|
||||||
})
|
})
|
||||||
|
|
@ -705,7 +705,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::String));
|
assert!(t == Some(ValueType::String));
|
||||||
let r = es.require_string(&v);
|
let r = es.require_string(&v);
|
||||||
assert!(r.is_err());
|
assert!(r.is_err());
|
||||||
assert!(r
|
assert!(r
|
||||||
|
|
@ -726,7 +726,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::String));
|
assert!(t == Some(ValueType::String));
|
||||||
// TODO
|
// TODO
|
||||||
// let r = es.require_string_without_context(&v);
|
// let r = es.require_string_without_context(&v);
|
||||||
// assert!(r.is_err());
|
// assert!(r.is_err());
|
||||||
|
|
@ -743,7 +743,7 @@ mod tests {
|
||||||
let v = es.new_value_str("hello").unwrap();
|
let v = es.new_value_str("hello").unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::String));
|
assert!(t == Some(ValueType::String));
|
||||||
let s = es.require_string(&v).unwrap();
|
let s = es.require_string(&v).unwrap();
|
||||||
assert!(s == "hello");
|
assert!(s == "hello");
|
||||||
})
|
})
|
||||||
|
|
@ -758,7 +758,7 @@ mod tests {
|
||||||
let v = es.new_value_str("").unwrap();
|
let v = es.new_value_str("").unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::String));
|
assert!(t == Some(ValueType::String));
|
||||||
let s = es.require_string(&v).unwrap();
|
let s = es.require_string(&v).unwrap();
|
||||||
assert!(s == "");
|
assert!(s == "");
|
||||||
})
|
})
|
||||||
|
|
@ -792,7 +792,7 @@ mod tests {
|
||||||
let v = es.new_value_int(42).unwrap();
|
let v = es.new_value_int(42).unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::Int));
|
assert!(t == Some(ValueType::Int));
|
||||||
let i = es.require_int(&v).unwrap();
|
let i = es.require_int(&v).unwrap();
|
||||||
assert!(i == 42);
|
assert!(i == 42);
|
||||||
})
|
})
|
||||||
|
|
@ -807,7 +807,7 @@ mod tests {
|
||||||
let v = es.eval_from_string("{ }", "<test>").unwrap();
|
let v = es.eval_from_string("{ }", "<test>").unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::AttrSet));
|
assert!(t == Some(ValueType::AttrSet));
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
@ -822,7 +822,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::List));
|
assert!(t == Some(ValueType::List));
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
@ -884,7 +884,7 @@ mod tests {
|
||||||
let v = es.call(f, a).unwrap();
|
let v = es.call(f, a).unwrap();
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::Int));
|
assert!(t == Some(ValueType::Int));
|
||||||
let i = es.require_int(&v).unwrap();
|
let i = es.require_int(&v).unwrap();
|
||||||
assert!(i == 3);
|
assert!(i == 3);
|
||||||
})
|
})
|
||||||
|
|
@ -900,10 +900,10 @@ mod tests {
|
||||||
let f = es.eval_from_string("x: x + 1", "<test>").unwrap();
|
let f = es.eval_from_string("x: x + 1", "<test>").unwrap();
|
||||||
let a = es.eval_from_string("2", "<test>").unwrap();
|
let a = es.eval_from_string("2", "<test>").unwrap();
|
||||||
let v = es.new_value_apply(&f, &a).unwrap();
|
let v = es.new_value_apply(&f, &a).unwrap();
|
||||||
assert!(es.value_type_unforced(&v) == ValueTypeOrThunk::Thunk);
|
assert!(es.value_type_unforced(&v) == None);
|
||||||
es.force(&v).unwrap();
|
es.force(&v).unwrap();
|
||||||
let t = es.value_type_unforced(&v);
|
let t = es.value_type_unforced(&v);
|
||||||
assert!(t == ValueTypeOrThunk::ValueType(ValueType::Int));
|
assert!(t == Some(ValueType::Int));
|
||||||
let i = es.require_int(&v).unwrap();
|
let i = es.require_int(&v).unwrap();
|
||||||
assert!(i == 3);
|
assert!(i == 3);
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -22,28 +22,29 @@ pub enum ValueType {
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
impl ValueType {
|
||||||
pub enum ValueTypeOrThunk {
|
/// Convert a raw value type to a `ValueType`.
|
||||||
ValueType(ValueType),
|
///
|
||||||
Thunk,
|
/// Return `None` if the Value is still a thunk (i.e. not yet evaluated).
|
||||||
}
|
///
|
||||||
|
/// Return `Some(ValueType::Unknown)` if the value type is not recognized.
|
||||||
impl ValueTypeOrThunk {
|
pub(crate) fn from_raw(raw: raw::ValueType) -> Option<ValueType> {
|
||||||
pub(crate) fn from_raw(raw: raw::ValueType) -> ValueTypeOrThunk {
|
|
||||||
match raw {
|
match raw {
|
||||||
raw::ValueType_NIX_TYPE_ATTRS => ValueTypeOrThunk::ValueType(ValueType::AttrSet),
|
raw::ValueType_NIX_TYPE_ATTRS => Some(ValueType::AttrSet),
|
||||||
raw::ValueType_NIX_TYPE_BOOL => ValueTypeOrThunk::ValueType(ValueType::Bool),
|
raw::ValueType_NIX_TYPE_BOOL => Some(ValueType::Bool),
|
||||||
raw::ValueType_NIX_TYPE_EXTERNAL => ValueTypeOrThunk::ValueType(ValueType::External),
|
raw::ValueType_NIX_TYPE_EXTERNAL => Some(ValueType::External),
|
||||||
raw::ValueType_NIX_TYPE_FLOAT => ValueTypeOrThunk::ValueType(ValueType::Float),
|
raw::ValueType_NIX_TYPE_FLOAT => Some(ValueType::Float),
|
||||||
raw::ValueType_NIX_TYPE_FUNCTION => ValueTypeOrThunk::ValueType(ValueType::Function),
|
raw::ValueType_NIX_TYPE_FUNCTION => Some(ValueType::Function),
|
||||||
raw::ValueType_NIX_TYPE_INT => ValueTypeOrThunk::ValueType(ValueType::Int),
|
raw::ValueType_NIX_TYPE_INT => Some(ValueType::Int),
|
||||||
raw::ValueType_NIX_TYPE_LIST => ValueTypeOrThunk::ValueType(ValueType::List),
|
raw::ValueType_NIX_TYPE_LIST => Some(ValueType::List),
|
||||||
raw::ValueType_NIX_TYPE_NULL => ValueTypeOrThunk::ValueType(ValueType::Null),
|
raw::ValueType_NIX_TYPE_NULL => Some(ValueType::Null),
|
||||||
raw::ValueType_NIX_TYPE_PATH => ValueTypeOrThunk::ValueType(ValueType::Path),
|
raw::ValueType_NIX_TYPE_PATH => Some(ValueType::Path),
|
||||||
raw::ValueType_NIX_TYPE_STRING => ValueTypeOrThunk::ValueType(ValueType::String),
|
raw::ValueType_NIX_TYPE_STRING => Some(ValueType::String),
|
||||||
raw::ValueType_NIX_TYPE_THUNK => ValueTypeOrThunk::Thunk,
|
|
||||||
|
raw::ValueType_NIX_TYPE_THUNK => None,
|
||||||
|
|
||||||
// This would happen if a new type of value is added in Nix.
|
// This would happen if a new type of value is added in Nix.
|
||||||
_ => ValueTypeOrThunk::ValueType(ValueType::Unknown),
|
_ => Some(ValueType::Unknown),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue