difftreelog
style fix clippy warnings
in: master
8 files changed
crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/arr/mod.rs
+++ b/crates/jrsonnet-evaluator/src/arr/mod.rs
@@ -1,7 +1,4 @@
-use std::{
- any::Any,
- num::{NonZeroU32, NonZeroUsize},
-};
+use std::{any::Any, num::NonZeroU32};
use jrsonnet_gcmodule::{Cc, Trace};
use jrsonnet_interner::IBytes;
crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
@@ -110,7 +110,11 @@
fn get(self: Box<Self>) -> Result<Self::Output> {
let full = self.full.evaluate()?;
let to = full.len() - self.end;
- Ok(Val::Arr(full.slice(Some(self.start as i32), Some(to as i32), None)))
+ Ok(Val::Arr(full.slice(
+ Some(self.start as i32),
+ Some(to as i32),
+ None,
+ )))
}
}
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth1use std::{2 cell::RefCell,3 fmt::{self, Debug, Display},4 mem::replace,5 num::{NonZeroU32, NonZeroUsize},6 rc::Rc,7};89use jrsonnet_gcmodule::{Cc, Trace};10use jrsonnet_interner::IStr;11use jrsonnet_types::ValType;1213pub use crate::arr::{ArrValue, ArrayLike};14use crate::{15 bail,16 error::{Error, ErrorKind::*},17 function::FuncVal,18 gc::{GcHashMap, TraceBox},19 manifest::{ManifestFormat, ToStringFormat},20 tb,21 typed::BoundedUsize,22 ObjValue, Result, Unbound, WeakObjValue,23};2425pub trait ThunkValue: Trace {26 type Output;27 fn get(self: Box<Self>) -> Result<Self::Output>;28}2930#[derive(Trace)]31enum ThunkInner<T: Trace> {32 Computed(T),33 Errored(Error),34 Waiting(TraceBox<dyn ThunkValue<Output = T>>),35 Pending,36}3738/// Lazily evaluated value39#[allow(clippy::module_name_repetitions)]40#[derive(Clone, Trace)]41pub struct Thunk<T: Trace>(Cc<RefCell<ThunkInner<T>>>);4243impl<T: Trace> Thunk<T> {44 pub fn evaluated(val: T) -> Self {45 Self(Cc::new(RefCell::new(ThunkInner::Computed(val))))46 }47 pub fn new(f: impl ThunkValue<Output = T> + 'static) -> Self {48 Self(Cc::new(RefCell::new(ThunkInner::Waiting(tb!(f)))))49 }50 pub fn errored(e: Error) -> Self {51 Self(Cc::new(RefCell::new(ThunkInner::Errored(e))))52 }53 pub fn result(res: Result<T, Error>) -> Self {54 match res {55 Ok(o) => Self::evaluated(o),56 Err(e) => Self::errored(e),57 }58 }59}6061impl<T> Thunk<T>62where63 T: Clone + Trace,64{65 pub fn force(&self) -> Result<()> {66 self.evaluate()?;67 Ok(())68 }6970 /// Evaluate thunk, or return cached value71 ///72 /// # Errors73 ///74 /// - Lazy value evaluation returned error75 /// - This method was called during inner value evaluation76 pub fn evaluate(&self) -> Result<T> {77 match &*self.0.borrow() {78 ThunkInner::Computed(v) => return Ok(v.clone()),79 ThunkInner::Errored(e) => return Err(e.clone()),80 ThunkInner::Pending => return Err(InfiniteRecursionDetected.into()),81 ThunkInner::Waiting(..) => (),82 };83 let ThunkInner::Waiting(value) = replace(&mut *self.0.borrow_mut(), ThunkInner::Pending)84 else {85 unreachable!();86 };87 let new_value = match value.0.get() {88 Ok(v) => v,89 Err(e) => {90 *self.0.borrow_mut() = ThunkInner::Errored(e.clone());91 return Err(e);92 }93 };94 *self.0.borrow_mut() = ThunkInner::Computed(new_value.clone());95 Ok(new_value)96 }97}9899pub trait ThunkMapper<Input>: Trace {100 type Output;101 fn map(self, from: Input) -> Result<Self::Output>;102}103impl<Input> Thunk<Input>104where105 Input: Trace + Clone,106{107 pub fn map<M>(self, mapper: M) -> Thunk<M::Output>108 where109 M: ThunkMapper<Input>,110 M::Output: Trace,111 {112 #[derive(Trace)]113 struct Mapped<Input: Trace, Mapper: Trace> {114 inner: Thunk<Input>,115 mapper: Mapper,116 }117 impl<Input, Mapper> ThunkValue for Mapped<Input, Mapper>118 where119 Input: Trace + Clone,120 Mapper: ThunkMapper<Input>,121 {122 type Output = Mapper::Output;123124 fn get(self: Box<Self>) -> Result<Self::Output> {125 let value = self.inner.evaluate()?;126 let mapped = self.mapper.map(value)?;127 Ok(mapped)128 }129 }130131 Thunk::new(Mapped::<Input, M> {132 inner: self,133 mapper,134 })135 }136}137138impl<T: Trace> From<Result<T>> for Thunk<T> {139 fn from(value: Result<T>) -> Self {140 match value {141 Ok(o) => Self::evaluated(o),142 Err(e) => Self::errored(e),143 }144 }145}146impl<T, V: Trace> From<T> for Thunk<V>147where148 T: ThunkValue<Output = V>,149{150 fn from(value: T) -> Self {151 Self::new(value)152 }153}154155impl<T: Trace + Default> Default for Thunk<T> {156 fn default() -> Self {157 Self::evaluated(T::default())158 }159}160161type CacheKey = (Option<WeakObjValue>, Option<WeakObjValue>);162163#[derive(Trace, Clone)]164pub struct CachedUnbound<I, T>165where166 I: Unbound<Bound = T>,167 T: Trace,168{169 cache: Cc<RefCell<GcHashMap<CacheKey, T>>>,170 value: I,171}172impl<I: Unbound<Bound = T>, T: Trace> CachedUnbound<I, T> {173 pub fn new(value: I) -> Self {174 Self {175 cache: Cc::new(RefCell::new(GcHashMap::new())),176 value,177 }178 }179}180impl<I: Unbound<Bound = T>, T: Clone + Trace> Unbound for CachedUnbound<I, T> {181 type Bound = T;182 fn bind(&self, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<T> {183 let cache_key = (184 sup.as_ref().map(|s| s.clone().downgrade()),185 this.as_ref().map(|t| t.clone().downgrade()),186 );187 {188 if let Some(t) = self.cache.borrow().get(&cache_key) {189 return Ok(t.clone());190 }191 }192 let bound = self.value.bind(sup, this)?;193194 {195 let mut cache = self.cache.borrow_mut();196 cache.insert(cache_key, bound.clone());197 }198199 Ok(bound)200 }201}202203impl<T: Debug + Trace> Debug for Thunk<T> {204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {205 write!(f, "Lazy")206 }207}208impl<T: Trace> PartialEq for Thunk<T> {209 fn eq(&self, other: &Self) -> bool {210 Cc::ptr_eq(&self.0, &other.0)211 }212}213214/// Represents a Jsonnet value, which can be sliced or indexed (string or array).215#[allow(clippy::module_name_repetitions)]216pub enum IndexableVal {217 /// String.218 Str(IStr),219 /// Array.220 Arr(ArrValue),221}222impl IndexableVal {223 pub fn to_array(self) -> ArrValue {224 match self {225 Self::Str(s) => ArrValue::chars(s.chars()),226 Self::Arr(arr) => arr,227 }228 }229 /// Slice the value.230 ///231 /// # Implementation232 ///233 /// For strings, will create a copy of specified interval.234 ///235 /// For arrays, nothing will be copied on this call, instead [`ArrValue::Slice`] view will be returned.236 pub fn slice(237 self,238 index: Option<i32>,239 end: Option<i32>,240 step: Option<BoundedUsize<1, { i32::MAX as usize }>>,241 ) -> Result<Self> {242 match &self {243 Self::Str(s) => {244 let mut computed_len = None;245 let mut get_len = || {246 computed_len.map_or_else(247 || {248 let len = s.chars().count();249 let _ = computed_len.insert(len);250 len251 },252 |len| len,253 )254 };255 let mut get_idx = |pos: Option<i32>, default| {256 match pos {257 Some(v) if v < 0 => get_len().saturating_sub((-v) as usize),258 // No need to clamp, as iterator interface is used259 Some(v) => v as usize,260 None => default,261 }262 };263264 let index = get_idx(index, 0);265 let end = get_idx(end, usize::MAX);266 let step = step.as_deref().copied().unwrap_or(1);267268 if index >= end {269 return Ok(Self::Str("".into()));270 }271272 Ok(Self::Str(273 (s.chars()274 .skip(index)275 .take(end - index)276 .step_by(step)277 .collect::<String>())278 .into(),279 ))280 }281 Self::Arr(arr) => Ok(Self::Arr(arr.clone().slice(282 index,283 end,284 step.map(|v| NonZeroU32::new(v.value() as u32).expect("bounded != 0")),285 ))),286 }287 }288}289290#[derive(Debug, Clone, Trace)]291pub enum StrValue {292 Flat(IStr),293 Tree(Rc<(StrValue, StrValue, usize)>),294}295impl StrValue {296 pub fn concat(a: Self, b: Self) -> Self {297 // TODO: benchmark for an optimal value, currently just a arbitrary choice298 const STRING_EXTEND_THRESHOLD: usize = 100;299300 if a.is_empty() {301 b302 } else if b.is_empty() {303 a304 } else if a.len() + b.len() < STRING_EXTEND_THRESHOLD {305 Self::Flat(format!("{a}{b}").into())306 } else {307 let len = a.len() + b.len();308 Self::Tree(Rc::new((a, b, len)))309 }310 }311 pub fn into_flat(self) -> IStr {312 #[cold]313 fn write_buf(s: &StrValue, out: &mut String) {314 match s {315 StrValue::Flat(f) => out.push_str(f),316 StrValue::Tree(t) => {317 write_buf(&t.0, out);318 write_buf(&t.1, out);319 }320 }321 }322 match self {323 Self::Flat(f) => f,324 Self::Tree(_) => {325 let mut buf = String::with_capacity(self.len());326 write_buf(&self, &mut buf);327 buf.into()328 }329 }330 }331 pub fn len(&self) -> usize {332 match self {333 Self::Flat(v) => v.len(),334 Self::Tree(t) => t.2,335 }336 }337 pub fn is_empty(&self) -> bool {338 match self {339 Self::Flat(v) => v.is_empty(),340 // Can't create non-flat empty string341 Self::Tree(_) => false,342 }343 }344}345impl<T> From<T> for StrValue346where347 IStr: From<T>,348{349 fn from(value: T) -> Self {350 Self::Flat(IStr::from(value))351 }352}353impl Display for StrValue {354 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {355 match self {356 Self::Flat(v) => write!(f, "{v}"),357 Self::Tree(t) => {358 write!(f, "{}", t.0)?;359 write!(f, "{}", t.1)360 }361 }362 }363}364impl PartialEq for StrValue {365 // False positive, into_flat returns not StrValue, but IStr, thus no infinite recursion here.366 #[allow(clippy::unconditional_recursion)]367 fn eq(&self, other: &Self) -> bool {368 let a = self.clone().into_flat();369 let b = other.clone().into_flat();370 a == b371 }372}373impl Eq for StrValue {}374impl PartialOrd for StrValue {375 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {376 Some(self.cmp(other))377 }378}379impl Ord for StrValue {380 fn cmp(&self, other: &Self) -> std::cmp::Ordering {381 let a = self.clone().into_flat();382 let b = other.clone().into_flat();383 a.cmp(&b)384 }385}386387/// Represents any valid Jsonnet value.388#[derive(Debug, Clone, Trace, Default)]389pub enum Val {390 /// Represents a Jsonnet boolean.391 Bool(bool),392 /// Represents a Jsonnet null value.393 #[default]394 Null,395 /// Represents a Jsonnet string.396 Str(StrValue),397 /// Represents a Jsonnet number.398 /// Should be finite, and not NaN399 /// This restriction isn't enforced by enum, as enum field can't be marked as private400 Num(f64),401 /// Experimental bigint402 #[cfg(feature = "exp-bigint")]403 BigInt(#[trace(skip)] Box<num_bigint::BigInt>),404 /// Represents a Jsonnet array.405 Arr(ArrValue),406 /// Represents a Jsonnet object.407 Obj(ObjValue),408 /// Represents a Jsonnet function.409 Func(FuncVal),410}411412#[cfg(target_pointer_width = "64")]413static_assertions::assert_eq_size!(Val, [u8; 24]);414415impl From<IndexableVal> for Val {416 fn from(v: IndexableVal) -> Self {417 match v {418 IndexableVal::Str(s) => Self::string(s),419 IndexableVal::Arr(a) => Self::Arr(a),420 }421 }422}423424impl Val {425 pub const fn as_bool(&self) -> Option<bool> {426 match self {427 Self::Bool(v) => Some(*v),428 _ => None,429 }430 }431 pub const fn as_null(&self) -> Option<()> {432 match self {433 Self::Null => Some(()),434 _ => None,435 }436 }437 pub fn as_str(&self) -> Option<IStr> {438 match self {439 Self::Str(s) => Some(s.clone().into_flat()),440 _ => None,441 }442 }443 pub const fn as_num(&self) -> Option<f64> {444 match self {445 Self::Num(n) => Some(*n),446 _ => None,447 }448 }449 pub fn as_arr(&self) -> Option<ArrValue> {450 match self {451 Self::Arr(a) => Some(a.clone()),452 _ => None,453 }454 }455 pub fn as_obj(&self) -> Option<ObjValue> {456 match self {457 Self::Obj(o) => Some(o.clone()),458 _ => None,459 }460 }461 pub fn as_func(&self) -> Option<FuncVal> {462 match self {463 Self::Func(f) => Some(f.clone()),464 _ => None,465 }466 }467468 /// Creates `Val::Num` after checking for numeric overflow.469 /// As numbers are `f64`, we can just check for their finity.470 pub fn new_checked_num(num: f64) -> Result<Self> {471 if num.is_finite() {472 Ok(Self::Num(num))473 } else {474 bail!("overflow")475 }476 }477478 pub const fn value_type(&self) -> ValType {479 match self {480 Self::Str(..) => ValType::Str,481 Self::Num(..) => ValType::Num,482 #[cfg(feature = "exp-bigint")]483 Self::BigInt(..) => ValType::BigInt,484 Self::Arr(..) => ValType::Arr,485 Self::Obj(..) => ValType::Obj,486 Self::Bool(_) => ValType::Bool,487 Self::Null => ValType::Null,488 Self::Func(..) => ValType::Func,489 }490 }491492 pub fn manifest(&self, format: impl ManifestFormat) -> Result<String> {493 fn manifest_dyn(val: &Val, manifest: &dyn ManifestFormat) -> Result<String> {494 manifest.manifest(val.clone())495 }496 manifest_dyn(self, &format)497 }498499 pub fn to_string(&self) -> Result<IStr> {500 Ok(match self {501 Self::Bool(true) => "true".into(),502 Self::Bool(false) => "false".into(),503 Self::Null => "null".into(),504 Self::Str(s) => s.clone().into_flat(),505 _ => self.manifest(ToStringFormat).map(IStr::from)?,506 })507 }508509 pub fn into_indexable(self) -> Result<IndexableVal> {510 Ok(match self {511 Self::Str(s) => IndexableVal::Str(s.into_flat()),512 Self::Arr(arr) => IndexableVal::Arr(arr),513 _ => bail!(ValueIsNotIndexable(self.value_type())),514 })515 }516517 pub fn function(function: impl Into<FuncVal>) -> Self {518 Self::Func(function.into())519 }520 pub fn string(string: impl Into<StrValue>) -> Self {521 Self::Str(string.into())522 }523}524525impl From<IStr> for Val {526 fn from(value: IStr) -> Self {527 Self::string(value)528 }529}530impl From<String> for Val {531 fn from(value: String) -> Self {532 Self::string(value)533 }534}535impl From<&str> for Val {536 fn from(value: &str) -> Self {537 Self::string(value)538 }539}540impl From<ObjValue> for Val {541 fn from(value: ObjValue) -> Self {542 Self::Obj(value)543 }544}545546const fn is_function_like(val: &Val) -> bool {547 matches!(val, Val::Func(_))548}549550/// Native implementation of `std.primitiveEquals`551pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {552 Ok(match (val_a, val_b) {553 (Val::Bool(a), Val::Bool(b)) => a == b,554 (Val::Null, Val::Null) => true,555 (Val::Str(a), Val::Str(b)) => a == b,556 (Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,557 #[cfg(feature = "exp-bigint")]558 (Val::BigInt(a), Val::BigInt(b)) => a == b,559 (Val::Arr(_), Val::Arr(_)) => {560 bail!("primitiveEquals operates on primitive types, got array")561 }562 (Val::Obj(_), Val::Obj(_)) => {563 bail!("primitiveEquals operates on primitive types, got object")564 }565 (a, b) if is_function_like(a) && is_function_like(b) => {566 bail!("cannot test equality of functions")567 }568 (_, _) => false,569 })570}571572/// Native implementation of `std.equals`573pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {574 if val_a.value_type() != val_b.value_type() {575 return Ok(false);576 }577 match (val_a, val_b) {578 (Val::Arr(a), Val::Arr(b)) => {579 if ArrValue::ptr_eq(a, b) {580 return Ok(true);581 }582 if a.len() != b.len() {583 return Ok(false);584 }585 for (a, b) in a.iter().zip(b.iter()) {586 if !equals(&a?, &b?)? {587 return Ok(false);588 }589 }590 Ok(true)591 }592 (Val::Obj(a), Val::Obj(b)) => {593 if ObjValue::ptr_eq(a, b) {594 return Ok(true);595 }596 let fields = a.fields(597 #[cfg(feature = "exp-preserve-order")]598 false,599 );600 if fields601 != b.fields(602 #[cfg(feature = "exp-preserve-order")]603 false,604 ) {605 return Ok(false);606 }607 for field in fields {608 if !equals(609 &a.get(field.clone())?.expect("field exists"),610 &b.get(field)?.expect("field exists"),611 )? {612 return Ok(false);613 }614 }615 Ok(true)616 }617 (a, b) => Ok(primitive_equals(a, b)?),618 }619}crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-macros/src/lib.rs
+++ b/crates/jrsonnet-macros/src/lib.rs
@@ -218,8 +218,7 @@
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let attr = parse_macro_input!(attr as BuiltinAttrs);
- let item_fn = item.clone();
- let item_fn: ItemFn = parse_macro_input!(item_fn);
+ let item_fn = parse_macro_input!(item as ItemFn);
match builtin_inner(attr, item_fn) {
Ok(v) => v.into(),
crates/jrsonnet-stdlib/src/manifest/toml.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/manifest/toml.rs
+++ b/crates/jrsonnet-stdlib/src/manifest/toml.rs
@@ -4,7 +4,7 @@
bail,
manifest::{escape_string_json_buf, ManifestFormat},
val::ArrValue,
- IStr, ObjValue, Result, ResultExt, Val, State,
+ IStr, ObjValue, Result, ResultExt, State, Val,
};
pub struct TomlFormat<'s> {
crates/jrsonnet-stdlib/src/manifest/xml.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/manifest/xml.rs
+++ b/crates/jrsonnet-stdlib/src/manifest/xml.rs
@@ -1,9 +1,9 @@
use jrsonnet_evaluator::{
bail,
manifest::{ManifestFormat, ToStringFormat},
- typed::{ComplexValType, Either2, Either4, Typed, ValType},
- val::{ArrValue, IndexableVal},
- Either, ObjValue, Result, ResultExt, Val, State,
+ typed::{ComplexValType, Either2, Typed, ValType},
+ val::ArrValue,
+ Either, ObjValue, Result, ResultExt, State, Val,
};
pub struct XmlJsonmlFormat {
@@ -39,20 +39,20 @@
fn from_untyped(untyped: Val) -> Result<Self> {
let val = <Either![ArrValue, String]>::from_untyped(untyped)
- .with_description(|| format!("parsing JSONML value (an array or string)"))?;
+ .description("parsing JSONML value (an array or string)")?;
let arr = match val {
Either2::A(a) => a,
Either2::B(s) => return Ok(Self::String(s)),
};
- if arr.len() < 1 {
+ if arr.is_empty() {
bail!("JSONML value should have tag (array length should be >=1)");
};
let tag = String::from_untyped(
arr.get(0)
- .with_description(|| "getting JSONML tag")?
+ .description("getting JSONML tag")?
.expect("length checked"),
)
- .with_description(|| format!("parsing JSONML tag"))?;
+ .description("parsing JSONML tag")?;
let (has_attrs, attrs) = if arr.len() >= 2 {
let maybe_attrs = arr
@@ -71,7 +71,7 @@
tag,
attrs,
children: State::push_description(
- || format!("parsing children"),
+ || "parsing children".to_owned(),
|| {
Typed::from_untyped(Val::Arr(arr.slice(
Some(if has_attrs { 2 } else { 1 }),
@@ -100,7 +100,7 @@
} => {
let has_children = !children.is_empty();
buf.push('<');
- buf.push_str(&tag);
+ buf.push_str(tag);
attrs.run_assertions()?;
for (key, value) in attrs.iter(
// Not much sense to preserve order here
@@ -125,12 +125,12 @@
}
buf.push('>');
for child in children {
- manifest_jsonml(&child, buf, opts)?;
+ manifest_jsonml(child, buf, opts)?;
}
if has_children || opts.force_closing {
buf.push('<');
buf.push('/');
- buf.push_str(&tag);
+ buf.push_str(tag);
buf.push('>');
}
Ok(())
@@ -177,8 +177,8 @@
}
if !found {
// No match - no escapes required
- out.push_str(&str);
+ out.push_str(str);
return;
}
- out.push_str(&remaining);
+ out.push_str(remaining);
}
crates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/misc.rs
+++ b/crates/jrsonnet-stdlib/src/misc.rs
@@ -28,8 +28,7 @@
o: ObjValue,
f: IStr,
default: Option<Thunk<Val>>,
- #[default(true)]
- inc_hidden: bool,
+ #[default(true)] inc_hidden: bool,
) -> Result<Val> {
let do_default = move || {
let Some(default) = default else {
crates/jrsonnet-stdlib/src/objects.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/objects.rs
+++ b/crates/jrsonnet-stdlib/src/objects.rs
@@ -57,8 +57,7 @@
o: ObjValue,
include_hidden: bool,
- #[cfg(feature = "exp-preserve-order")]
- preserve_order: bool,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: bool,
) -> ArrValue {
o.values_ex(
include_hidden,
@@ -101,8 +100,7 @@
o: ObjValue,
include_hidden: bool,
- #[cfg(feature = "exp-preserve-order")]
- preserve_order: bool,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: bool,
) -> ArrValue {
o.key_values_ex(
include_hidden,