difftreelog
refactor switch to jrsonnet-gc
in: master
27 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -100,27 +100,6 @@
]
[[package]]
-name = "gc"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3edaac0f5832202ebc99520cb77c932248010c4645d20be1dc62d6579f5b3752"
-dependencies = [
- "gc_derive",
-]
-
-[[package]]
-name = "gc_derive"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60df8444f094ff7885631d80e78eb7d88c3c2361a98daaabb06256e4500db941"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
-
-[[package]]
name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -190,7 +169,7 @@
"anyhow",
"base64",
"bincode",
- "gc",
+ "jrsonnet-gc",
"jrsonnet-interner",
"jrsonnet-parser",
"jrsonnet-stdlib",
@@ -204,10 +183,31 @@
]
[[package]]
+name = "jrsonnet-gc"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68da8bc2f00117b1373bb8877af03b1d391e4c4800e6585d7279e5b99c919dde"
+dependencies = [
+ "jrsonnet-gc-derive",
+]
+
+[[package]]
+name = "jrsonnet-gc-derive"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adcba9c387b64b054f06cc4d724905296e21edeeb7506847f3299117a2d92d12"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
name = "jrsonnet-interner"
version = "0.3.8"
dependencies = [
- "gc",
+ "jrsonnet-gc",
"rustc-hash",
"serde",
]
@@ -216,7 +216,7 @@
name = "jrsonnet-parser"
version = "0.3.8"
dependencies = [
- "gc",
+ "jrsonnet-gc",
"jrsonnet-interner",
"jrsonnet-stdlib",
"peg",
@@ -232,7 +232,7 @@
name = "jrsonnet-types"
version = "0.3.8"
dependencies = [
- "gc",
+ "jrsonnet-gc",
"peg",
]
@@ -240,8 +240,8 @@
name = "jsonnet"
version = "0.3.8"
dependencies = [
- "gc",
"jrsonnet-evaluator",
+ "jrsonnet-gc",
"jrsonnet-parser",
]
bindings/jsonnet/Cargo.tomldiffbeforeafterboth--- a/bindings/jsonnet/Cargo.toml
+++ b/bindings/jsonnet/Cargo.toml
@@ -10,7 +10,7 @@
[dependencies]
jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.3.8" }
jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.3.8" }
-gc = { version = "0.4.1", features = ["derive"] }
+jrsonnet-gc = { version = "0.4.2", features = ["derive"] }
[lib]
crate-type = ["cdylib"]
bindings/jsonnet/src/native.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/native.rs
+++ b/bindings/jsonnet/src/native.rs
@@ -1,9 +1,9 @@
-use gc::{unsafe_empty_trace, Finalize, Gc, Trace};
use jrsonnet_evaluator::{
error::{Error, LocError},
native::{NativeCallback, NativeCallbackHandler},
EvaluationState, Val,
};
+use jrsonnet_gc::{unsafe_empty_trace, Finalize, Gc, Trace};
use jrsonnet_parser::{Param, ParamsDesc};
use std::{
ffi::{c_void, CStr},
bindings/jsonnet/src/val_make.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/val_make.rs
+++ b/bindings/jsonnet/src/val_make.rs
@@ -1,7 +1,7 @@
//! Create values in VM
-use gc::Gc;
use jrsonnet_evaluator::{ArrValue, EvaluationState, ObjValue, Val};
+use jrsonnet_gc::Gc;
use std::{
ffi::CStr,
os::raw::{c_char, c_double, c_int},
bindings/jsonnet/src/val_modify.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/val_modify.rs
+++ b/bindings/jsonnet/src/val_modify.rs
@@ -2,8 +2,8 @@
//! Only tested with variables, which haven't altered by code before appearing here
//! In jrsonnet every value is immutable, and this code is probally broken
-use gc::Gc;
use jrsonnet_evaluator::{ArrValue, EvaluationState, LazyBinding, LazyVal, ObjMember, Val};
+use jrsonnet_gc::Gc;
use jrsonnet_parser::Visibility;
use std::{ffi::CStr, os::raw::c_char};
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -35,7 +35,7 @@
rustc-hash = "1.1.0"
thiserror = "1.0"
-gc = { version = "0.4.1", features = ["derive"] }
+jrsonnet-gc = { version = "0.4.2", features = ["derive"] }
[dependencies.anyhow]
version = "1.0"
crates/jrsonnet-evaluator/src/builtin/format.rsdiffbeforeafterboth1//! faster std.format impl2#![allow(clippy::too_many_arguments)]34use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val};5use gc::{Finalize, Trace};6use jrsonnet_interner::IStr;7use jrsonnet_types::ValType;8use thiserror::Error;910#[derive(Debug, Clone, Error, Trace, Finalize)]11pub enum FormatError {12 #[error("truncated format code")]13 TruncatedFormatCode,14 #[error("unrecognized conversion type: {0}")]15 UnrecognizedConversionType(char),1617 #[error("not enough values")]18 NotEnoughValues,1920 #[error("cannot use * width with object")]21 CannotUseStarWidthWithObject,22 #[error("mapping keys required")]23 MappingKeysRequired,24 #[error("no such format field: {0}")]25 NoSuchFormatField(IStr),26}2728impl From<FormatError> for LocError {29 fn from(e: FormatError) -> Self {30 Self::new(Format(e))31 }32}3334use FormatError::*;3536type ParseResult<'t, T> = std::result::Result<(T, &'t str), FormatError>;3738pub fn try_parse_mapping_key(str: &str) -> ParseResult<&str> {39 if str.is_empty() {40 return Err(TruncatedFormatCode);41 }42 let bytes = str.as_bytes();43 if bytes[0] == b'(' {44 let mut i = 1;45 while i < bytes.len() {46 if bytes[i] == b')' {47 return Ok((&str[1..i as usize], &str[i as usize + 1..]));48 }49 i += 1;50 }51 Err(TruncatedFormatCode)52 } else {53 Ok(("", str))54 }55}5657#[cfg(test)]58pub mod tests_key {59 use super::*;6061 #[test]62 fn parse_key() {63 assert_eq!(64 try_parse_mapping_key("(hello ) world").unwrap(),65 ("hello ", " world")66 );67 assert_eq!(try_parse_mapping_key("() world").unwrap(), ("", " world"));68 assert_eq!(try_parse_mapping_key(" world").unwrap(), ("", " world"));69 assert_eq!(70 try_parse_mapping_key(" () world").unwrap(),71 ("", " () world")72 );73 }7475 #[test]76 #[should_panic]77 fn parse_key_missing_start() {78 try_parse_mapping_key("").unwrap();79 }8081 #[test]82 #[should_panic]83 fn parse_key_missing_end() {84 try_parse_mapping_key("( ").unwrap();85 }86}8788#[derive(Default, Debug)]89pub struct CFlags {90 pub alt: bool,91 pub zero: bool,92 pub left: bool,93 pub blank: bool,94 pub sign: bool,95}9697pub fn try_parse_cflags(str: &str) -> ParseResult<CFlags> {98 if str.is_empty() {99 return Err(TruncatedFormatCode);100 }101 let bytes = str.as_bytes();102 let mut i = 0;103 let mut out = CFlags::default();104 loop {105 if bytes.len() == i {106 return Err(TruncatedFormatCode);107 }108 match bytes[i] {109 b'#' => out.alt = true,110 b'0' => out.zero = true,111 b'-' => out.left = true,112 b' ' => out.blank = true,113 b'+' => out.sign = true,114 _ => break,115 }116 i += 1;117 }118 Ok((out, &str[i..]))119}120121#[derive(Debug, PartialEq)]122pub enum Width {123 Star,124 Fixed(usize),125}126pub fn try_parse_field_width(str: &str) -> ParseResult<Width> {127 if str.is_empty() {128 return Err(TruncatedFormatCode);129 }130 let bytes = str.as_bytes();131 if bytes[0] == b'*' {132 return Ok((Width::Star, &str[1..]));133 }134 let mut out: usize = 0;135 let mut digits = 0;136 while let Some(digit) = (bytes[digits] as char).to_digit(10) {137 out *= 10;138 out += digit as usize;139 digits += 1;140 if digits == bytes.len() {141 return Err(TruncatedFormatCode);142 }143 }144 Ok((Width::Fixed(out), &str[digits..]))145}146147pub fn try_parse_precision(str: &str) -> ParseResult<Option<Width>> {148 if str.is_empty() {149 return Err(TruncatedFormatCode);150 }151 let bytes = str.as_bytes();152 if bytes[0] == b'.' {153 try_parse_field_width(&str[1..]).map(|(r, s)| (Some(r), s))154 } else {155 Ok((None, str))156 }157}158159// Only skips160pub fn try_parse_length_modifier(str: &str) -> ParseResult<()> {161 if str.is_empty() {162 return Err(TruncatedFormatCode);163 }164 let bytes = str.as_bytes();165 let mut idx = 0;166 while bytes[idx] == b'h' || bytes[idx] == b'l' || bytes[idx] == b'L' {167 idx += 1;168 if bytes.len() == idx {169 return Err(TruncatedFormatCode);170 }171 }172 Ok(((), &str[idx..]))173}174175#[derive(Debug, PartialEq)]176pub enum ConvTypeV {177 Decimal,178 Octal,179 Hexadecimal,180 Scientific,181 Float,182 Shorter,183 Char,184 String,185 Percent,186}187pub struct ConvType {188 v: ConvTypeV,189 caps: bool,190}191192pub fn parse_conversion_type(str: &str) -> ParseResult<ConvType> {193 if str.is_empty() {194 return Err(TruncatedFormatCode);195 }196197 let code = str.as_bytes()[0];198 let v: (ConvTypeV, bool) = match code {199 b'd' | b'i' | b'u' => (ConvTypeV::Decimal, false),200 b'o' => (ConvTypeV::Octal, false),201 b'x' => (ConvTypeV::Hexadecimal, false),202 b'X' => (ConvTypeV::Hexadecimal, true),203 b'e' => (ConvTypeV::Scientific, false),204 b'E' => (ConvTypeV::Scientific, true),205 b'f' => (ConvTypeV::Float, false),206 b'F' => (ConvTypeV::Float, true),207 b'g' => (ConvTypeV::Shorter, false),208 b'G' => (ConvTypeV::Shorter, true),209 b'c' => (ConvTypeV::Char, false),210 b's' => (ConvTypeV::String, false),211 b'%' => (ConvTypeV::Percent, false),212 c => return Err(UnrecognizedConversionType(c as char)),213 };214215 Ok((ConvType { v: v.0, caps: v.1 }, &str[1..]))216}217218#[derive(Debug)]219pub struct Code<'s> {220 mkey: &'s str,221 cflags: CFlags,222 width: Width,223 precision: Option<Width>,224 convtype: ConvTypeV,225 caps: bool,226}227pub fn parse_code(str: &str) -> ParseResult<Code> {228 if str.is_empty() {229 return Err(TruncatedFormatCode);230 }231 let (mkey, str) = try_parse_mapping_key(str)?;232 let (cflags, str) = try_parse_cflags(str)?;233 let (width, str) = try_parse_field_width(str)?;234 let (precision, str) = try_parse_precision(str)?;235 let (_, str) = try_parse_length_modifier(str)?;236 let (convtype, str) = parse_conversion_type(str)?;237238 Ok((239 Code {240 mkey,241 cflags,242 width,243 precision,244 convtype: convtype.v,245 caps: convtype.caps,246 },247 str,248 ))249}250251#[derive(Debug)]252pub enum Element<'s> {253 String(&'s str),254 Code(Code<'s>),255}256pub fn parse_codes(mut str: &str) -> Result<Vec<Element>> {257 let mut bytes = str.as_bytes();258 let mut out = vec![];259 let mut offset = 0;260261 loop {262 while offset != bytes.len() && bytes[offset] != b'%' {263 offset += 1;264 }265 if offset != 0 {266 out.push(Element::String(&str[0..offset]));267 }268 if offset == bytes.len() {269 return Ok(out);270 }271 str = &str[offset + 1..];272 let (code, nstr) = parse_code(str)?;273 str = nstr;274 bytes = str.as_bytes();275 offset = 0;276277 out.push(Element::Code(code))278 }279}280281const NUMBERS: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyz";282283#[inline]284pub fn render_integer(285 out: &mut String,286 iv: i64,287 padding: usize,288 precision: usize,289 blank: bool,290 sign: bool,291 radix: i64,292 prefix: &str,293 caps: bool,294) {295 // Digit char indexes in reverse order, i.e296 // for radix = 16 and n = 12f: [15, 2, 1]297 let digits = if iv == 0 {298 vec![0u8]299 } else {300 let mut v = iv.abs();301 let mut nums = Vec::with_capacity(1);302 while v > 0 {303 nums.push((v % radix) as u8);304 v /= radix;305 }306 nums307 };308 let neg = iv < 0;309 let zp = padding.saturating_sub(if neg || blank || sign { 1 } else { 0 });310 let zp2 = zp311 .max(precision)312 .saturating_sub(prefix.len() + digits.len());313314 if neg {315 out.push('-')316 } else if sign {317 out.push('+');318 } else if blank {319 out.push(' ');320 }321322 out.reserve(zp2);323 for _ in 0..zp2 {324 out.push('0');325 }326 out.push_str(prefix);327328 for digit in digits.into_iter().rev() {329 let ch = NUMBERS[digit as usize] as char;330 out.push(if caps { ch.to_ascii_uppercase() } else { ch });331 }332}333334pub fn render_decimal(335 out: &mut String,336 iv: i64,337 padding: usize,338 precision: usize,339 blank: bool,340 sign: bool,341) {342 render_integer(out, iv, padding, precision, blank, sign, 10, "", false)343}344pub fn render_octal(345 out: &mut String,346 iv: i64,347 padding: usize,348 precision: usize,349 alt: bool,350 blank: bool,351 sign: bool,352) {353 render_integer(354 out,355 iv,356 padding,357 precision,358 blank,359 sign,360 8,361 if alt && iv != 0 { "0" } else { "" },362 false,363 )364}365pub fn render_hexadecimal(366 out: &mut String,367 iv: i64,368 padding: usize,369 precision: usize,370 alt: bool,371 blank: bool,372 sign: bool,373 caps: bool,374) {375 render_integer(376 out,377 iv,378 padding,379 precision,380 blank,381 sign,382 16,383 match (alt, caps) {384 (true, true) => "0X",385 (true, false) => "0x",386 (false, _) => "",387 },388 caps,389 )390}391392pub fn render_float(393 out: &mut String,394 n: f64,395 mut padding: usize,396 precision: usize,397 blank: bool,398 sign: bool,399 ensure_pt: bool,400 trailing: bool,401) {402 let dot_size = if precision == 0 && !ensure_pt { 0 } else { 1 };403 padding = padding.saturating_sub(dot_size + precision);404 render_decimal(out, n.floor() as i64, padding, 0, blank, sign);405 if precision == 0 {406 if ensure_pt {407 out.push('.');408 }409 return;410 }411 let frac = n412 .fract()413 .mul_add(10.0_f64.powf(precision as f64), 0.5)414 .floor();415 if trailing || frac > 0.0 {416 out.push('.');417 let mut frac_str = String::new();418 render_decimal(&mut frac_str, frac as i64, precision, 0, false, false);419 let mut trim = frac_str.len();420 if !trailing {421 for b in frac_str.as_bytes().iter().rev() {422 if *b == b'0' {423 trim -= 1;424 }425 }426 }427 out.push_str(&frac_str[..trim]);428 } else if ensure_pt {429 out.push('.');430 }431}432433pub fn render_float_sci(434 out: &mut String,435 n: f64,436 mut padding: usize,437 precision: usize,438 blank: bool,439 sign: bool,440 ensure_pt: bool,441 trailing: bool,442 caps: bool,443) {444 let exponent = n.log10().floor();445 let mantissa = if exponent as i16 == -324 {446 n * 10.0 / 10.0_f64.powf(exponent + 1.0)447 } else {448 n / 10.0_f64.powf(exponent)449 };450 let mut exponent_str = String::new();451 render_decimal(&mut exponent_str, exponent as i64, 3, 0, false, true);452453 // +1 for e454 padding = padding.saturating_sub(exponent_str.len() + 1);455456 render_float(457 out, mantissa, padding, precision, blank, sign, ensure_pt, trailing,458 );459 out.push(if caps { 'E' } else { 'e' });460 out.push_str(&exponent_str);461}462463pub fn format_code(464 out: &mut String,465 value: &Val,466 code: &Code,467 width: usize,468 precision: Option<usize>,469) -> Result<()> {470 let clfags = &code.cflags;471 let (fpprec, iprec) = match precision {472 Some(v) => (v, v),473 None => (6, 0),474 };475 let padding = if clfags.zero && !clfags.left {476 width477 } else {478 0479 };480481 // TODO: If left padded, can optimize by writing directly to out482 let mut tmp_out = String::new();483484 match code.convtype {485 ConvTypeV::String => tmp_out.push_str(&value.clone().to_string()?),486 ConvTypeV::Decimal => {487 let value = value.clone().try_cast_num("%d/%u/%i requires number")?;488 render_decimal(489 &mut tmp_out,490 value as i64,491 padding,492 iprec,493 clfags.blank,494 clfags.sign,495 );496 }497 ConvTypeV::Octal => {498 let value = value.clone().try_cast_num("%o requires number")?;499 render_octal(500 &mut tmp_out,501 value as i64,502 padding,503 iprec,504 clfags.alt,505 clfags.blank,506 clfags.sign,507 );508 }509 ConvTypeV::Hexadecimal => {510 let value = value.clone().try_cast_num("%x/%X requires number")?;511 render_hexadecimal(512 &mut tmp_out,513 value as i64,514 padding,515 iprec,516 clfags.alt,517 clfags.blank,518 clfags.sign,519 code.caps,520 );521 }522 ConvTypeV::Scientific => {523 let value = value.clone().try_cast_num("%e/%E requires number")?;524 render_float_sci(525 &mut tmp_out,526 value,527 padding,528 fpprec,529 clfags.blank,530 clfags.sign,531 clfags.alt,532 true,533 code.caps,534 );535 }536 ConvTypeV::Float => {537 let value = value.clone().try_cast_num("%e/%E requires number")?;538 render_float(539 &mut tmp_out,540 value,541 padding,542 fpprec,543 clfags.blank,544 clfags.sign,545 clfags.alt,546 true,547 );548 }549 ConvTypeV::Shorter => {550 let value = value.clone().try_cast_num("%g/%G requires number")?;551 let exponent = value.log10().floor();552 if exponent < -4.0 || exponent >= fpprec as f64 {553 render_float_sci(554 &mut tmp_out,555 value,556 padding,557 fpprec - 1,558 clfags.blank,559 clfags.sign,560 clfags.alt,561 clfags.alt,562 code.caps,563 );564 } else {565 let digits_before_pt = 1.max(exponent as usize + 1);566 render_float(567 &mut tmp_out,568 value,569 padding,570 fpprec - digits_before_pt,571 clfags.blank,572 clfags.sign,573 clfags.alt,574 clfags.alt,575 );576 }577 }578 ConvTypeV::Char => match value.clone() {579 Val::Num(n) => tmp_out.push(580 std::char::from_u32(n as u32)581 .ok_or_else(|| InvalidUnicodeCodepointGot(n as u32))?,582 ),583 Val::Str(s) => {584 if s.chars().count() != 1 {585 throw!(RuntimeError(586 format!("%c expected 1 char string, got {}", s.chars().count()).into(),587 ));588 }589 tmp_out.push_str(&s);590 }591 _ => {592 throw!(TypeMismatch(593 "%c requires number/string",594 vec![ValType::Num, ValType::Str],595 value.value_type(),596 ));597 }598 },599 ConvTypeV::Percent => tmp_out.push('%'),600 };601602 let padding = width.saturating_sub(tmp_out.len());603604 if !clfags.left {605 for _ in 0..padding {606 out.push(' ');607 }608 }609 out.push_str(&tmp_out);610 if clfags.left {611 for _ in 0..padding {612 out.push(' ');613 }614 }615616 Ok(())617}618619pub fn format_arr(str: &str, mut values: &[Val]) -> Result<String> {620 let codes = parse_codes(str)?;621 let mut out = String::new();622623 for code in codes {624 match code {625 Element::String(s) => {626 out.push_str(s);627 }628 Element::Code(c) => {629 let width = match c.width {630 Width::Star => {631 if values.is_empty() {632 throw!(NotEnoughValues);633 }634 let value = &values[0];635 values = &values[1..];636 value.clone().try_cast_num("field width")? as usize637 }638 Width::Fixed(n) => n,639 };640 let precision = match c.precision {641 Some(Width::Star) => {642 if values.is_empty() {643 throw!(NotEnoughValues);644 }645 let value = &values[0];646 values = &values[1..];647 Some(value.clone().try_cast_num("field precision")? as usize)648 }649 Some(Width::Fixed(n)) => Some(n),650 None => None,651 };652653 // %% should not consume a value654 let value = if c.convtype == ConvTypeV::Percent {655 &Val::Null656 } else {657 if values.is_empty() {658 throw!(NotEnoughValues);659 }660 let value = &values[0];661 values = &values[1..];662 value663 };664665 format_code(&mut out, value, &c, width, precision)?;666 }667 }668 }669670 Ok(out)671}672673pub fn format_obj(str: &str, values: &ObjValue) -> Result<String> {674 let codes = parse_codes(str)?;675 let mut out = String::new();676677 for code in codes {678 match code {679 Element::String(s) => {680 out.push_str(s);681 }682 Element::Code(c) => {683 // TODO: Operate on ref684 let f: IStr = c.mkey.into();685 let width = match c.width {686 Width::Star => {687 throw!(CannotUseStarWidthWithObject);688 }689 Width::Fixed(n) => n,690 };691 let precision = match c.precision {692 Some(Width::Star) => {693 throw!(CannotUseStarWidthWithObject);694 }695 Some(Width::Fixed(n)) => Some(n),696 None => None,697 };698699 let value = if c.convtype == ConvTypeV::Percent {700 Val::Null701 } else {702 if f.is_empty() {703 throw!(MappingKeysRequired);704 }705 if let Some(v) = values.get(f.clone())? {706 v707 } else {708 throw!(NoSuchFormatField(f));709 }710 };711712 format_code(&mut out, &value, &c, width, precision)?;713 }714 }715 }716717 Ok(out)718}719720#[cfg(test)]721pub mod test_format {722 use super::*;723724 #[test]725 fn parse() {726 assert_eq!(727 parse_codes(728 "How much error budget is left looking at our %.3f%% availability gurantees?"729 )730 .unwrap()731 .len(),732 4733 );734 }735736 #[test]737 fn octals() {738 assert_eq!(format_arr("%#o", &[Val::Num(8.0)]).unwrap(), "010");739 assert_eq!(format_arr("%#4o", &[Val::Num(8.0)]).unwrap(), " 010");740 assert_eq!(format_arr("%4o", &[Val::Num(8.0)]).unwrap(), " 10");741 assert_eq!(format_arr("%04o", &[Val::Num(8.0)]).unwrap(), "0010");742 assert_eq!(format_arr("%+4o", &[Val::Num(8.0)]).unwrap(), " +10");743 assert_eq!(format_arr("%+04o", &[Val::Num(8.0)]).unwrap(), "+010");744 assert_eq!(format_arr("%-4o", &[Val::Num(8.0)]).unwrap(), "10 ");745 assert_eq!(format_arr("%+-4o", &[Val::Num(8.0)]).unwrap(), "+10 ");746 assert_eq!(format_arr("%+-04o", &[Val::Num(8.0)]).unwrap(), "+10 ");747 }748749 #[test]750 fn percent_doesnt_consumes_values() {751 assert_eq!(752 format_arr(753 "How much error budget is left looking at our %.3f%% availability gurantees?",754 &[Val::Num(4.0)]755 )756 .unwrap(),757 "How much error budget is left looking at our 4.000% availability gurantees?"758 );759 }760}1//! faster std.format impl2#![allow(clippy::too_many_arguments)]34use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val};5use jrsonnet_gc::Trace;6use jrsonnet_interner::IStr;7use jrsonnet_types::ValType;8use thiserror::Error;910#[derive(Debug, Clone, Error, Trace)]11#[trivially_drop]12pub enum FormatError {13 #[error("truncated format code")]14 TruncatedFormatCode,15 #[error("unrecognized conversion type: {0}")]16 UnrecognizedConversionType(char),1718 #[error("not enough values")]19 NotEnoughValues,2021 #[error("cannot use * width with object")]22 CannotUseStarWidthWithObject,23 #[error("mapping keys required")]24 MappingKeysRequired,25 #[error("no such format field: {0}")]26 NoSuchFormatField(IStr),27}2829impl From<FormatError> for LocError {30 fn from(e: FormatError) -> Self {31 Self::new(Format(e))32 }33}3435use FormatError::*;3637type ParseResult<'t, T> = std::result::Result<(T, &'t str), FormatError>;3839pub fn try_parse_mapping_key(str: &str) -> ParseResult<&str> {40 if str.is_empty() {41 return Err(TruncatedFormatCode);42 }43 let bytes = str.as_bytes();44 if bytes[0] == b'(' {45 let mut i = 1;46 while i < bytes.len() {47 if bytes[i] == b')' {48 return Ok((&str[1..i as usize], &str[i as usize + 1..]));49 }50 i += 1;51 }52 Err(TruncatedFormatCode)53 } else {54 Ok(("", str))55 }56}5758#[cfg(test)]59pub mod tests_key {60 use super::*;6162 #[test]63 fn parse_key() {64 assert_eq!(65 try_parse_mapping_key("(hello ) world").unwrap(),66 ("hello ", " world")67 );68 assert_eq!(try_parse_mapping_key("() world").unwrap(), ("", " world"));69 assert_eq!(try_parse_mapping_key(" world").unwrap(), ("", " world"));70 assert_eq!(71 try_parse_mapping_key(" () world").unwrap(),72 ("", " () world")73 );74 }7576 #[test]77 #[should_panic]78 fn parse_key_missing_start() {79 try_parse_mapping_key("").unwrap();80 }8182 #[test]83 #[should_panic]84 fn parse_key_missing_end() {85 try_parse_mapping_key("( ").unwrap();86 }87}8889#[derive(Default, Debug)]90pub struct CFlags {91 pub alt: bool,92 pub zero: bool,93 pub left: bool,94 pub blank: bool,95 pub sign: bool,96}9798pub fn try_parse_cflags(str: &str) -> ParseResult<CFlags> {99 if str.is_empty() {100 return Err(TruncatedFormatCode);101 }102 let bytes = str.as_bytes();103 let mut i = 0;104 let mut out = CFlags::default();105 loop {106 if bytes.len() == i {107 return Err(TruncatedFormatCode);108 }109 match bytes[i] {110 b'#' => out.alt = true,111 b'0' => out.zero = true,112 b'-' => out.left = true,113 b' ' => out.blank = true,114 b'+' => out.sign = true,115 _ => break,116 }117 i += 1;118 }119 Ok((out, &str[i..]))120}121122#[derive(Debug, PartialEq)]123pub enum Width {124 Star,125 Fixed(usize),126}127pub fn try_parse_field_width(str: &str) -> ParseResult<Width> {128 if str.is_empty() {129 return Err(TruncatedFormatCode);130 }131 let bytes = str.as_bytes();132 if bytes[0] == b'*' {133 return Ok((Width::Star, &str[1..]));134 }135 let mut out: usize = 0;136 let mut digits = 0;137 while let Some(digit) = (bytes[digits] as char).to_digit(10) {138 out *= 10;139 out += digit as usize;140 digits += 1;141 if digits == bytes.len() {142 return Err(TruncatedFormatCode);143 }144 }145 Ok((Width::Fixed(out), &str[digits..]))146}147148pub fn try_parse_precision(str: &str) -> ParseResult<Option<Width>> {149 if str.is_empty() {150 return Err(TruncatedFormatCode);151 }152 let bytes = str.as_bytes();153 if bytes[0] == b'.' {154 try_parse_field_width(&str[1..]).map(|(r, s)| (Some(r), s))155 } else {156 Ok((None, str))157 }158}159160// Only skips161pub fn try_parse_length_modifier(str: &str) -> ParseResult<()> {162 if str.is_empty() {163 return Err(TruncatedFormatCode);164 }165 let bytes = str.as_bytes();166 let mut idx = 0;167 while bytes[idx] == b'h' || bytes[idx] == b'l' || bytes[idx] == b'L' {168 idx += 1;169 if bytes.len() == idx {170 return Err(TruncatedFormatCode);171 }172 }173 Ok(((), &str[idx..]))174}175176#[derive(Debug, PartialEq)]177pub enum ConvTypeV {178 Decimal,179 Octal,180 Hexadecimal,181 Scientific,182 Float,183 Shorter,184 Char,185 String,186 Percent,187}188pub struct ConvType {189 v: ConvTypeV,190 caps: bool,191}192193pub fn parse_conversion_type(str: &str) -> ParseResult<ConvType> {194 if str.is_empty() {195 return Err(TruncatedFormatCode);196 }197198 let code = str.as_bytes()[0];199 let v: (ConvTypeV, bool) = match code {200 b'd' | b'i' | b'u' => (ConvTypeV::Decimal, false),201 b'o' => (ConvTypeV::Octal, false),202 b'x' => (ConvTypeV::Hexadecimal, false),203 b'X' => (ConvTypeV::Hexadecimal, true),204 b'e' => (ConvTypeV::Scientific, false),205 b'E' => (ConvTypeV::Scientific, true),206 b'f' => (ConvTypeV::Float, false),207 b'F' => (ConvTypeV::Float, true),208 b'g' => (ConvTypeV::Shorter, false),209 b'G' => (ConvTypeV::Shorter, true),210 b'c' => (ConvTypeV::Char, false),211 b's' => (ConvTypeV::String, false),212 b'%' => (ConvTypeV::Percent, false),213 c => return Err(UnrecognizedConversionType(c as char)),214 };215216 Ok((ConvType { v: v.0, caps: v.1 }, &str[1..]))217}218219#[derive(Debug)]220pub struct Code<'s> {221 mkey: &'s str,222 cflags: CFlags,223 width: Width,224 precision: Option<Width>,225 convtype: ConvTypeV,226 caps: bool,227}228pub fn parse_code(str: &str) -> ParseResult<Code> {229 if str.is_empty() {230 return Err(TruncatedFormatCode);231 }232 let (mkey, str) = try_parse_mapping_key(str)?;233 let (cflags, str) = try_parse_cflags(str)?;234 let (width, str) = try_parse_field_width(str)?;235 let (precision, str) = try_parse_precision(str)?;236 let (_, str) = try_parse_length_modifier(str)?;237 let (convtype, str) = parse_conversion_type(str)?;238239 Ok((240 Code {241 mkey,242 cflags,243 width,244 precision,245 convtype: convtype.v,246 caps: convtype.caps,247 },248 str,249 ))250}251252#[derive(Debug)]253pub enum Element<'s> {254 String(&'s str),255 Code(Code<'s>),256}257pub fn parse_codes(mut str: &str) -> Result<Vec<Element>> {258 let mut bytes = str.as_bytes();259 let mut out = vec![];260 let mut offset = 0;261262 loop {263 while offset != bytes.len() && bytes[offset] != b'%' {264 offset += 1;265 }266 if offset != 0 {267 out.push(Element::String(&str[0..offset]));268 }269 if offset == bytes.len() {270 return Ok(out);271 }272 str = &str[offset + 1..];273 let (code, nstr) = parse_code(str)?;274 str = nstr;275 bytes = str.as_bytes();276 offset = 0;277278 out.push(Element::Code(code))279 }280}281282const NUMBERS: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyz";283284#[inline]285pub fn render_integer(286 out: &mut String,287 iv: i64,288 padding: usize,289 precision: usize,290 blank: bool,291 sign: bool,292 radix: i64,293 prefix: &str,294 caps: bool,295) {296 // Digit char indexes in reverse order, i.e297 // for radix = 16 and n = 12f: [15, 2, 1]298 let digits = if iv == 0 {299 vec![0u8]300 } else {301 let mut v = iv.abs();302 let mut nums = Vec::with_capacity(1);303 while v > 0 {304 nums.push((v % radix) as u8);305 v /= radix;306 }307 nums308 };309 let neg = iv < 0;310 let zp = padding.saturating_sub(if neg || blank || sign { 1 } else { 0 });311 let zp2 = zp312 .max(precision)313 .saturating_sub(prefix.len() + digits.len());314315 if neg {316 out.push('-')317 } else if sign {318 out.push('+');319 } else if blank {320 out.push(' ');321 }322323 out.reserve(zp2);324 for _ in 0..zp2 {325 out.push('0');326 }327 out.push_str(prefix);328329 for digit in digits.into_iter().rev() {330 let ch = NUMBERS[digit as usize] as char;331 out.push(if caps { ch.to_ascii_uppercase() } else { ch });332 }333}334335pub fn render_decimal(336 out: &mut String,337 iv: i64,338 padding: usize,339 precision: usize,340 blank: bool,341 sign: bool,342) {343 render_integer(out, iv, padding, precision, blank, sign, 10, "", false)344}345pub fn render_octal(346 out: &mut String,347 iv: i64,348 padding: usize,349 precision: usize,350 alt: bool,351 blank: bool,352 sign: bool,353) {354 render_integer(355 out,356 iv,357 padding,358 precision,359 blank,360 sign,361 8,362 if alt && iv != 0 { "0" } else { "" },363 false,364 )365}366pub fn render_hexadecimal(367 out: &mut String,368 iv: i64,369 padding: usize,370 precision: usize,371 alt: bool,372 blank: bool,373 sign: bool,374 caps: bool,375) {376 render_integer(377 out,378 iv,379 padding,380 precision,381 blank,382 sign,383 16,384 match (alt, caps) {385 (true, true) => "0X",386 (true, false) => "0x",387 (false, _) => "",388 },389 caps,390 )391}392393pub fn render_float(394 out: &mut String,395 n: f64,396 mut padding: usize,397 precision: usize,398 blank: bool,399 sign: bool,400 ensure_pt: bool,401 trailing: bool,402) {403 let dot_size = if precision == 0 && !ensure_pt { 0 } else { 1 };404 padding = padding.saturating_sub(dot_size + precision);405 render_decimal(out, n.floor() as i64, padding, 0, blank, sign);406 if precision == 0 {407 if ensure_pt {408 out.push('.');409 }410 return;411 }412 let frac = n413 .fract()414 .mul_add(10.0_f64.powf(precision as f64), 0.5)415 .floor();416 if trailing || frac > 0.0 {417 out.push('.');418 let mut frac_str = String::new();419 render_decimal(&mut frac_str, frac as i64, precision, 0, false, false);420 let mut trim = frac_str.len();421 if !trailing {422 for b in frac_str.as_bytes().iter().rev() {423 if *b == b'0' {424 trim -= 1;425 }426 }427 }428 out.push_str(&frac_str[..trim]);429 } else if ensure_pt {430 out.push('.');431 }432}433434pub fn render_float_sci(435 out: &mut String,436 n: f64,437 mut padding: usize,438 precision: usize,439 blank: bool,440 sign: bool,441 ensure_pt: bool,442 trailing: bool,443 caps: bool,444) {445 let exponent = n.log10().floor();446 let mantissa = if exponent as i16 == -324 {447 n * 10.0 / 10.0_f64.powf(exponent + 1.0)448 } else {449 n / 10.0_f64.powf(exponent)450 };451 let mut exponent_str = String::new();452 render_decimal(&mut exponent_str, exponent as i64, 3, 0, false, true);453454 // +1 for e455 padding = padding.saturating_sub(exponent_str.len() + 1);456457 render_float(458 out, mantissa, padding, precision, blank, sign, ensure_pt, trailing,459 );460 out.push(if caps { 'E' } else { 'e' });461 out.push_str(&exponent_str);462}463464pub fn format_code(465 out: &mut String,466 value: &Val,467 code: &Code,468 width: usize,469 precision: Option<usize>,470) -> Result<()> {471 let clfags = &code.cflags;472 let (fpprec, iprec) = match precision {473 Some(v) => (v, v),474 None => (6, 0),475 };476 let padding = if clfags.zero && !clfags.left {477 width478 } else {479 0480 };481482 // TODO: If left padded, can optimize by writing directly to out483 let mut tmp_out = String::new();484485 match code.convtype {486 ConvTypeV::String => tmp_out.push_str(&value.clone().to_string()?),487 ConvTypeV::Decimal => {488 let value = value.clone().try_cast_num("%d/%u/%i requires number")?;489 render_decimal(490 &mut tmp_out,491 value as i64,492 padding,493 iprec,494 clfags.blank,495 clfags.sign,496 );497 }498 ConvTypeV::Octal => {499 let value = value.clone().try_cast_num("%o requires number")?;500 render_octal(501 &mut tmp_out,502 value as i64,503 padding,504 iprec,505 clfags.alt,506 clfags.blank,507 clfags.sign,508 );509 }510 ConvTypeV::Hexadecimal => {511 let value = value.clone().try_cast_num("%x/%X requires number")?;512 render_hexadecimal(513 &mut tmp_out,514 value as i64,515 padding,516 iprec,517 clfags.alt,518 clfags.blank,519 clfags.sign,520 code.caps,521 );522 }523 ConvTypeV::Scientific => {524 let value = value.clone().try_cast_num("%e/%E requires number")?;525 render_float_sci(526 &mut tmp_out,527 value,528 padding,529 fpprec,530 clfags.blank,531 clfags.sign,532 clfags.alt,533 true,534 code.caps,535 );536 }537 ConvTypeV::Float => {538 let value = value.clone().try_cast_num("%e/%E requires number")?;539 render_float(540 &mut tmp_out,541 value,542 padding,543 fpprec,544 clfags.blank,545 clfags.sign,546 clfags.alt,547 true,548 );549 }550 ConvTypeV::Shorter => {551 let value = value.clone().try_cast_num("%g/%G requires number")?;552 let exponent = value.log10().floor();553 if exponent < -4.0 || exponent >= fpprec as f64 {554 render_float_sci(555 &mut tmp_out,556 value,557 padding,558 fpprec - 1,559 clfags.blank,560 clfags.sign,561 clfags.alt,562 clfags.alt,563 code.caps,564 );565 } else {566 let digits_before_pt = 1.max(exponent as usize + 1);567 render_float(568 &mut tmp_out,569 value,570 padding,571 fpprec - digits_before_pt,572 clfags.blank,573 clfags.sign,574 clfags.alt,575 clfags.alt,576 );577 }578 }579 ConvTypeV::Char => match value.clone() {580 Val::Num(n) => tmp_out.push(581 std::char::from_u32(n as u32)582 .ok_or_else(|| InvalidUnicodeCodepointGot(n as u32))?,583 ),584 Val::Str(s) => {585 if s.chars().count() != 1 {586 throw!(RuntimeError(587 format!("%c expected 1 char string, got {}", s.chars().count()).into(),588 ));589 }590 tmp_out.push_str(&s);591 }592 _ => {593 throw!(TypeMismatch(594 "%c requires number/string",595 vec![ValType::Num, ValType::Str],596 value.value_type(),597 ));598 }599 },600 ConvTypeV::Percent => tmp_out.push('%'),601 };602603 let padding = width.saturating_sub(tmp_out.len());604605 if !clfags.left {606 for _ in 0..padding {607 out.push(' ');608 }609 }610 out.push_str(&tmp_out);611 if clfags.left {612 for _ in 0..padding {613 out.push(' ');614 }615 }616617 Ok(())618}619620pub fn format_arr(str: &str, mut values: &[Val]) -> Result<String> {621 let codes = parse_codes(str)?;622 let mut out = String::new();623624 for code in codes {625 match code {626 Element::String(s) => {627 out.push_str(s);628 }629 Element::Code(c) => {630 let width = match c.width {631 Width::Star => {632 if values.is_empty() {633 throw!(NotEnoughValues);634 }635 let value = &values[0];636 values = &values[1..];637 value.clone().try_cast_num("field width")? as usize638 }639 Width::Fixed(n) => n,640 };641 let precision = match c.precision {642 Some(Width::Star) => {643 if values.is_empty() {644 throw!(NotEnoughValues);645 }646 let value = &values[0];647 values = &values[1..];648 Some(value.clone().try_cast_num("field precision")? as usize)649 }650 Some(Width::Fixed(n)) => Some(n),651 None => None,652 };653654 // %% should not consume a value655 let value = if c.convtype == ConvTypeV::Percent {656 &Val::Null657 } else {658 if values.is_empty() {659 throw!(NotEnoughValues);660 }661 let value = &values[0];662 values = &values[1..];663 value664 };665666 format_code(&mut out, value, &c, width, precision)?;667 }668 }669 }670671 Ok(out)672}673674pub fn format_obj(str: &str, values: &ObjValue) -> Result<String> {675 let codes = parse_codes(str)?;676 let mut out = String::new();677678 for code in codes {679 match code {680 Element::String(s) => {681 out.push_str(s);682 }683 Element::Code(c) => {684 // TODO: Operate on ref685 let f: IStr = c.mkey.into();686 let width = match c.width {687 Width::Star => {688 throw!(CannotUseStarWidthWithObject);689 }690 Width::Fixed(n) => n,691 };692 let precision = match c.precision {693 Some(Width::Star) => {694 throw!(CannotUseStarWidthWithObject);695 }696 Some(Width::Fixed(n)) => Some(n),697 None => None,698 };699700 let value = if c.convtype == ConvTypeV::Percent {701 Val::Null702 } else {703 if f.is_empty() {704 throw!(MappingKeysRequired);705 }706 if let Some(v) = values.get(f.clone())? {707 v708 } else {709 throw!(NoSuchFormatField(f));710 }711 };712713 format_code(&mut out, &value, &c, width, precision)?;714 }715 }716 }717718 Ok(out)719}720721#[cfg(test)]722pub mod test_format {723 use super::*;724725 #[test]726 fn parse() {727 assert_eq!(728 parse_codes(729 "How much error budget is left looking at our %.3f%% availability gurantees?"730 )731 .unwrap()732 .len(),733 4734 );735 }736737 #[test]738 fn octals() {739 assert_eq!(format_arr("%#o", &[Val::Num(8.0)]).unwrap(), "010");740 assert_eq!(format_arr("%#4o", &[Val::Num(8.0)]).unwrap(), " 010");741 assert_eq!(format_arr("%4o", &[Val::Num(8.0)]).unwrap(), " 10");742 assert_eq!(format_arr("%04o", &[Val::Num(8.0)]).unwrap(), "0010");743 assert_eq!(format_arr("%+4o", &[Val::Num(8.0)]).unwrap(), " +10");744 assert_eq!(format_arr("%+04o", &[Val::Num(8.0)]).unwrap(), "+010");745 assert_eq!(format_arr("%-4o", &[Val::Num(8.0)]).unwrap(), "10 ");746 assert_eq!(format_arr("%+-4o", &[Val::Num(8.0)]).unwrap(), "+10 ");747 assert_eq!(format_arr("%+-04o", &[Val::Num(8.0)]).unwrap(), "+10 ");748 }749750 #[test]751 fn percent_doesnt_consumes_values() {752 assert_eq!(753 format_arr(754 "How much error budget is left looking at our %.3f%% availability gurantees?",755 &[Val::Num(4.0)]756 )757 .unwrap(),758 "How much error budget is left looking at our 4.000% availability gurantees?"759 );760 }761}crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -5,7 +5,7 @@
EvaluationState, FuncVal, LazyVal, Val,
};
use format::{format_arr, format_obj};
-use gc::Gc;
+use jrsonnet_gc::Gc;
use jrsonnet_interner::IStr;
use jrsonnet_parser::{ArgsDesc, BinaryOpType, ExprLocation};
use jrsonnet_types::ty;
@@ -454,7 +454,7 @@
0, rest: ty!(any);
], {
println!("GC start");
- gc::force_collect();
+ jrsonnet_gc::force_collect();
println!("GC done");
Ok(rest)
crates/jrsonnet-evaluator/src/builtin/sort.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/sort.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/sort.rs
@@ -2,7 +2,7 @@
error::{Error, LocError, Result},
throw, Context, FuncVal, Val,
};
-use gc::{Finalize, Gc, Trace};
+use jrsonnet_gc::{Finalize, Gc, Trace};
#[derive(Debug, Clone, thiserror::Error, Trace, Finalize)]
pub enum SortError {
crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/ctx.rs
+++ b/crates/jrsonnet-evaluator/src/ctx.rs
@@ -2,13 +2,14 @@
error::Error::*, map::LayeredHashMap, FutureWrapper, LazyBinding, LazyVal, ObjValue, Result,
Val,
};
-use gc::{Finalize, Gc, Trace};
+use jrsonnet_gc::{Gc, Trace};
use jrsonnet_interner::IStr;
use rustc_hash::FxHashMap;
use std::fmt::Debug;
use std::hash::BuildHasherDefault;
-#[derive(Clone, Trace, Finalize)]
+#[derive(Clone, Trace)]
+#[trivially_drop]
pub struct ContextCreator(pub Context, pub FutureWrapper<FxHashMap<IStr, LazyBinding>>);
impl ContextCreator {
pub fn create(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<Context> {
@@ -21,12 +22,13 @@
}
}
-#[derive(Trace, Finalize)]
+#[derive(Trace)]
+#[trivially_drop]
struct ContextInternals {
dollar: Option<ObjValue>,
this: Option<ObjValue>,
super_obj: Option<ObjValue>,
- bindings: LayeredHashMap<LazyVal>,
+ bindings: LayeredHashMap,
}
impl Debug for ContextInternals {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -34,7 +36,8 @@
}
}
-#[derive(Debug, Clone, Trace, Finalize)]
+#[derive(Debug, Clone, Trace)]
+#[trivially_drop]
pub struct Context(Gc<ContextInternals>);
impl Context {
pub fn new_future() -> FutureWrapper<Self> {
crates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/dynamic.rs
+++ b/crates/jrsonnet-evaluator/src/dynamic.rs
@@ -1,6 +1,7 @@
-use gc::{Finalize, Gc, GcCell, Trace};
+use jrsonnet_gc::{Gc, GcCell, Trace};
-#[derive(Clone, Trace, Finalize)]
+#[derive(Clone, Trace)]
+#[trivially_drop]
pub struct FutureWrapper<V: Trace + 'static>(pub Gc<GcCell<Option<V>>>);
impl<T: Trace + 'static> FutureWrapper<T> {
pub fn new() -> Self {
crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -2,7 +2,7 @@
builtin::{format::FormatError, sort::SortError},
typed::TypeLocError,
};
-use gc::{Finalize, Trace};
+use jrsonnet_gc::Trace;
use jrsonnet_interner::IStr;
use jrsonnet_parser::{BinaryOpType, ExprLocation, UnaryOpType};
use jrsonnet_types::ValType;
@@ -12,7 +12,8 @@
};
use thiserror::Error;
-#[derive(Error, Debug, Clone, Trace, Finalize)]
+#[derive(Error, Debug, Clone, Trace)]
+#[trivially_drop]
pub enum Error {
#[error("intrinsic not found: {0}")]
IntrinsicNotFound(IStr),
@@ -149,15 +150,18 @@
}
}
-#[derive(Clone, Debug, Trace, Finalize)]
+#[derive(Clone, Debug, Trace)]
+#[trivially_drop]
pub struct StackTraceElement {
pub location: Option<ExprLocation>,
pub desc: String,
}
-#[derive(Debug, Clone, Trace, Finalize)]
+#[derive(Debug, Clone, Trace)]
+#[trivially_drop]
pub struct StackTrace(pub Vec<StackTraceElement>);
-#[derive(Debug, Clone, Trace, Finalize)]
+#[derive(Debug, Clone, Trace)]
+#[trivially_drop]
pub struct LocError(Box<(Error, StackTrace)>);
impl LocError {
pub fn new(e: Error) -> Self {
crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -3,7 +3,7 @@
FuncDesc, FuncVal, FutureWrapper, LazyBinding, LazyVal, LazyValValue, ObjMember, ObjValue,
ObjectAssertion, Result, Val,
};
-use gc::{custom_trace, Finalize, Gc, Trace};
+use jrsonnet_gc::{Gc, Trace};
use jrsonnet_interner::IStr;
use jrsonnet_parser::{
ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, ExprLocation, FieldMember,
@@ -22,21 +22,14 @@
if let Some(params) = &b.params {
let params = params.clone();
+ #[derive(Trace)]
+ #[trivially_drop]
struct LazyMethodBinding {
context_creator: FutureWrapper<Context>,
name: IStr,
params: ParamsDesc,
value: LocExpr,
}
- impl Finalize for LazyMethodBinding {}
- unsafe impl Trace for LazyMethodBinding {
- custom_trace!(this, {
- mark(&this.context_creator);
- mark(&this.name);
- mark(&this.params);
- mark(&this.value);
- });
- }
impl LazyValValue for LazyMethodBinding {
fn get(self: Box<Self>) -> Result<Val> {
Ok(evaluate_method(
@@ -55,19 +48,13 @@
value: b.value.clone(),
}))
} else {
+ #[derive(Trace)]
+ #[trivially_drop]
struct LazyNamedBinding {
context_creator: FutureWrapper<Context>,
name: IStr,
value: LocExpr,
}
- impl Finalize for LazyNamedBinding {}
- unsafe impl Trace for LazyNamedBinding {
- custom_trace!(this, {
- mark(&this.context_creator);
- mark(&this.name);
- mark(&this.value);
- });
- }
impl LazyValValue for LazyNamedBinding {
fn get(self: Box<Self>) -> Result<Val> {
evaluate_named(self.context_creator.unwrap(), &self.value, self.name)
@@ -86,6 +73,8 @@
if let Some(params) = &b.params {
let params = params.clone();
+ #[derive(Trace)]
+ #[trivially_drop]
struct BindableMethodLazyVal {
this: Option<ObjValue>,
super_obj: Option<ObjValue>,
@@ -94,17 +83,6 @@
name: IStr,
params: ParamsDesc,
value: LocExpr,
- }
- impl Finalize for BindableMethodLazyVal {}
- unsafe impl Trace for BindableMethodLazyVal {
- custom_trace!(this, {
- mark(&this.this);
- mark(&this.super_obj);
- mark(&this.context_creator);
- mark(&this.name);
- mark(&this.params);
- mark(&this.value);
- });
}
impl LazyValValue for BindableMethodLazyVal {
fn get(self: Box<Self>) -> Result<Val> {
@@ -117,7 +95,8 @@
}
}
- #[derive(Trace, Finalize)]
+ #[derive(Trace)]
+ #[trivially_drop]
struct BindableMethod {
context_creator: ContextCreator,
name: IStr,
@@ -148,6 +127,8 @@
}))),
)
} else {
+ #[derive(Trace)]
+ #[trivially_drop]
struct BindableNamedLazyVal {
this: Option<ObjValue>,
super_obj: Option<ObjValue>,
@@ -156,16 +137,6 @@
name: IStr,
value: LocExpr,
}
- impl Finalize for BindableNamedLazyVal {}
- unsafe impl Trace for BindableNamedLazyVal {
- custom_trace!(this, {
- mark(&this.this);
- mark(&this.super_obj);
- mark(&this.context_creator);
- mark(&this.name);
- mark(&this.value);
- });
- }
impl LazyValValue for BindableNamedLazyVal {
fn get(self: Box<Self>) -> Result<Val> {
evaluate_named(
@@ -176,7 +147,8 @@
}
}
- #[derive(Trace, Finalize)]
+ #[derive(Trace)]
+ #[trivially_drop]
struct BindableNamed {
context_creator: ContextCreator,
name: IStr,
@@ -414,7 +386,8 @@
}
let name = name.unwrap();
- #[derive(Trace, Finalize)]
+ #[derive(Trace)]
+ #[trivially_drop]
struct ObjMemberBinding {
context_creator: ContextCreator,
value: LocExpr,
@@ -458,7 +431,8 @@
continue;
}
let name = name.unwrap();
- #[derive(Trace, Finalize)]
+ #[derive(Trace)]
+ #[trivially_drop]
struct ObjMemberBinding {
context_creator: ContextCreator,
value: LocExpr,
@@ -496,16 +470,11 @@
}
Member::BindStmt(_) => {}
Member::AssertStmt(stmt) => {
+ #[derive(Trace)]
+ #[trivially_drop]
struct ObjectAssert {
context_creator: ContextCreator,
assert: AssertStmt,
- }
- impl Finalize for ObjectAssert {}
- unsafe impl Trace for ObjectAssert {
- custom_trace!(this, {
- mark(&this.context_creator);
- mark(&this.assert);
- });
}
impl ObjectAssertion for ObjectAssert {
fn run(
@@ -558,7 +527,8 @@
match key {
Val::Null => {}
Val::Str(n) => {
- #[derive(Trace, Finalize)]
+ #[derive(Trace)]
+ #[trivially_drop]
struct ObjCompBinding {
context: Context,
value: LocExpr,
@@ -768,16 +738,11 @@
let mut out = Vec::with_capacity(items.len());
for item in items {
// TODO: Implement ArrValue::Lazy with same context for every element?
+ #[derive(Trace)]
+ #[trivially_drop]
struct ArrayElement {
context: Context,
item: LocExpr,
- }
- impl Finalize for ArrayElement {}
- unsafe impl Trace for ArrayElement {
- custom_trace!(this, {
- mark(&this.context);
- mark(&this.item);
- });
}
impl LazyValValue for ArrayElement {
fn get(self: Box<Self>) -> Result<Val> {
crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -1,5 +1,5 @@
use crate::{error::Error::*, evaluate, throw, Context, LazyVal, LazyValValue, Result, Val};
-use gc::{custom_trace, Finalize, Trace};
+use jrsonnet_gc::Trace;
use jrsonnet_interner::IStr;
use jrsonnet_parser::{ArgsDesc, LocExpr, ParamsDesc};
use rustc_hash::FxHashMap;
@@ -55,16 +55,11 @@
let val = if tailstrict {
LazyVal::new_resolved(evaluate(ctx, expr)?)
} else {
+ #[derive(Trace)]
+ #[trivially_drop]
struct EvaluateLazyVal {
context: Context,
expr: LocExpr,
- }
- impl Finalize for EvaluateLazyVal {}
- unsafe impl Trace for EvaluateLazyVal {
- custom_trace!(this, {
- mark(&this.context);
- mark(&this.expr);
- });
}
impl LazyValValue for EvaluateLazyVal {
fn get(self: Box<Self>) -> Result<Val> {
@@ -119,7 +114,8 @@
} else {
let body_ctx = body_ctx.clone();
let default = default.clone();
- #[derive(Trace, Finalize)]
+ #[derive(Trace)]
+ #[trivially_drop]
struct EvaluateLazyVal {
body_ctx: Option<Context>,
default: LocExpr,
crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/integrations/serde.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs
@@ -2,7 +2,7 @@
error::{Error::*, LocError, Result},
throw, LazyBinding, LazyVal, ObjMember, ObjValue, Val,
};
-use gc::Gc;
+use jrsonnet_gc::Gc;
use jrsonnet_parser::Visibility;
use rustc_hash::FxHasher;
use serde_json::{Map, Number, Value};
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -25,8 +25,8 @@
use error::{Error::*, LocError, Result, StackTraceElement};
pub use evaluate::*;
pub use function::parse_function_call;
-use gc::{Finalize, Gc, Trace};
pub use import::*;
+use jrsonnet_gc::{Finalize, Gc, Trace};
pub use jrsonnet_interner::IStr;
use jrsonnet_parser::*;
use native::NativeCallback;
crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/map.rs
+++ b/crates/jrsonnet-evaluator/src/map.rs
@@ -1,32 +1,29 @@
-use gc::{Finalize, Gc, Trace};
+use jrsonnet_gc::{Gc, Trace};
use jrsonnet_interner::IStr;
use rustc_hash::FxHashMap;
-pub struct LayeredHashMapInternals<V: Trace + Finalize + 'static> {
- parent: Option<LayeredHashMap<V>>,
- current: FxHashMap<IStr, V>,
-}
+use crate::LazyVal;
-unsafe impl<V: Trace + Finalize + 'static> Trace for LayeredHashMapInternals<V> {
- gc::custom_trace!(this, {
- mark(&this.parent);
- mark(&this.current);
- });
+#[derive(Trace)]
+#[trivially_drop]
+pub struct LayeredHashMapInternals {
+ parent: Option<LayeredHashMap>,
+ current: FxHashMap<IStr, LazyVal>,
}
-impl<V: Trace + Finalize + 'static> Finalize for LayeredHashMapInternals<V> {}
-#[derive(Trace, Finalize)]
-pub struct LayeredHashMap<V: Trace + Finalize + 'static>(Gc<LayeredHashMapInternals<V>>);
+#[derive(Trace)]
+#[trivially_drop]
+pub struct LayeredHashMap(Gc<LayeredHashMapInternals>);
-impl<V: Trace + 'static> LayeredHashMap<V> {
- pub fn extend(self, new_layer: FxHashMap<IStr, V>) -> Self {
+impl LayeredHashMap {
+ pub fn extend(self, new_layer: FxHashMap<IStr, LazyVal>) -> Self {
Self(Gc::new(LayeredHashMapInternals {
parent: Some(self),
current: new_layer,
}))
}
- pub fn get(&self, key: &IStr) -> Option<&V> {
+ pub fn get(&self, key: &IStr) -> Option<&LazyVal> {
(self.0)
.current
.get(key)
@@ -34,13 +31,13 @@
}
}
-impl<V: Trace + 'static> Clone for LayeredHashMap<V> {
+impl Clone for LayeredHashMap {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
-impl<V: Trace + 'static> Default for LayeredHashMap<V> {
+impl Default for LayeredHashMap {
fn default() -> Self {
Self(Gc::new(LayeredHashMapInternals {
parent: None,
crates/jrsonnet-evaluator/src/native.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/native.rs
+++ b/crates/jrsonnet-evaluator/src/native.rs
@@ -1,7 +1,7 @@
#![allow(clippy::type_complexity)]
use crate::{error::Result, Val};
-use gc::{Finalize, Trace};
+use jrsonnet_gc::Trace;
use jrsonnet_parser::ParamsDesc;
use std::fmt::Debug;
use std::path::Path;
@@ -11,7 +11,8 @@
fn call(&self, from: Option<Rc<Path>>, args: &[Val]) -> Result<Val>;
}
-#[derive(Trace, Finalize)]
+#[derive(Trace)]
+#[trivially_drop]
pub struct NativeCallback {
pub params: ParamsDesc,
handler: Box<dyn NativeCallbackHandler>,
crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/obj.rs
+++ b/crates/jrsonnet-evaluator/src/obj.rs
@@ -1,12 +1,13 @@
use crate::{evaluate_add_op, LazyBinding, Result, Val};
-use gc::{Finalize, Gc, GcCell, Trace};
+use jrsonnet_gc::{Gc, GcCell, Trace};
use jrsonnet_interner::IStr;
use jrsonnet_parser::{ExprLocation, Visibility};
use rustc_hash::{FxHashMap, FxHashSet};
use std::hash::{Hash, Hasher};
use std::{fmt::Debug, hash::BuildHasherDefault};
-#[derive(Debug, Trace, Finalize)]
+#[derive(Debug, Trace)]
+#[trivially_drop]
pub struct ObjMember {
pub add: bool,
pub visibility: Visibility,
@@ -20,7 +21,8 @@
// Field => This
type CacheKey = (IStr, ObjValue);
-#[derive(Trace, Finalize)]
+#[derive(Trace)]
+#[trivially_drop]
pub struct ObjValueInternals {
super_obj: Option<ObjValue>,
assertions: Gc<Vec<Box<dyn ObjectAssertion>>>,
@@ -30,7 +32,8 @@
value_cache: GcCell<FxHashMap<CacheKey, Option<Val>>>,
}
-#[derive(Clone, Trace, Finalize)]
+#[derive(Clone, Trace)]
+#[trivially_drop]
pub struct ObjValue(pub(crate) Gc<ObjValueInternals>);
impl Debug for ObjValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
crates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/typed.rs
+++ b/crates/jrsonnet-evaluator/src/typed.rs
@@ -4,7 +4,7 @@
error::{Error, LocError, Result},
push, Val,
};
-use gc::{Finalize, Trace};
+use jrsonnet_gc::Trace;
use jrsonnet_parser::ExprLocation;
use jrsonnet_types::{ComplexValType, ValType};
use thiserror::Error;
@@ -21,7 +21,8 @@
}};
}
-#[derive(Debug, Error, Clone, Trace, Finalize)]
+#[derive(Debug, Error, Clone, Trace)]
+#[trivially_drop]
pub enum TypeError {
#[error("expected {0}, got {1}")]
ExpectedGot(ComplexValType, ValType),
@@ -38,7 +39,8 @@
}
}
-#[derive(Debug, Clone, Trace, Finalize)]
+#[derive(Debug, Clone, Trace)]
+#[trivially_drop]
pub struct TypeLocError(Box<TypeError>, ValuePathStack);
impl From<TypeError> for TypeLocError {
fn from(e: TypeError) -> Self {
@@ -60,7 +62,8 @@
}
}
-#[derive(Debug, Clone, Trace, Finalize)]
+#[derive(Debug, Clone, Trace)]
+#[trivially_drop]
pub struct TypeLocErrorList(Vec<TypeLocError>);
impl Display for TypeLocErrorList {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -123,7 +126,8 @@
}
}
-#[derive(Clone, Debug, Trace, Finalize)]
+#[derive(Clone, Debug, Trace)]
+#[trivially_drop]
enum ValuePathItem {
Field(Rc<str>),
Index(u64),
@@ -138,7 +142,8 @@
}
}
-#[derive(Clone, Debug, Trace, Finalize)]
+#[derive(Clone, Debug, Trace)]
+#[trivially_drop]
struct ValuePathStack(Vec<ValuePathItem>);
impl Display for ValuePathStack {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -9,7 +9,7 @@
native::NativeCallback,
throw, with_state, Context, ObjValue, Result,
};
-use gc::{custom_trace, Finalize, Gc, GcCell, Trace};
+use jrsonnet_gc::{Finalize, Gc, GcCell, Trace};
use jrsonnet_interner::IStr;
use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, ExprLocation, LiteralType, LocExpr, ParamsDesc};
use jrsonnet_types::ValType;
@@ -19,25 +19,17 @@
fn get(self: Box<Self>) -> Result<Val>;
}
+#[derive(Trace)]
+#[trivially_drop]
enum LazyValInternals {
Computed(Val),
Errored(LocError),
Waiting(Box<dyn LazyValValue>),
Pending,
-}
-impl Finalize for LazyValInternals {}
-unsafe impl Trace for LazyValInternals {
- custom_trace!(this, {
- match &this {
- LazyValInternals::Computed(v) => mark(v),
- LazyValInternals::Errored(e) => mark(e),
- LazyValInternals::Waiting(w) => mark(w),
- LazyValInternals::Pending => {}
- }
- });
}
-#[derive(Clone, Trace, Finalize)]
+#[derive(Clone, Trace)]
+#[trivially_drop]
pub struct LazyVal(Gc<GcCell<LazyValInternals>>);
impl LazyVal {
pub fn new(f: Box<dyn LazyValValue>) -> Self {
@@ -83,7 +75,8 @@
}
}
-#[derive(Debug, PartialEq, Trace, Finalize)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub struct FuncDesc {
pub name: IStr,
pub ctx: Context,
@@ -91,7 +84,8 @@
pub body: LocExpr,
}
-#[derive(Debug, Trace, Finalize)]
+#[derive(Debug, Trace)]
+#[trivially_drop]
pub enum FuncVal {
/// Plain function implemented in jsonnet
Normal(FuncDesc),
@@ -195,22 +189,13 @@
String,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Trace)]
+#[trivially_drop]
pub enum ArrValue {
Lazy(Gc<Vec<LazyVal>>),
Eager(Gc<Vec<Val>>),
Extended(Box<(Self, Self)>),
}
-impl Finalize for ArrValue {}
-unsafe impl Trace for ArrValue {
- custom_trace!(this, {
- match &this {
- ArrValue::Lazy(l) => mark(l),
- ArrValue::Eager(e) => mark(e),
- ArrValue::Extended(x) => mark(x),
- }
- });
-}
impl ArrValue {
pub fn new_eager() -> Self {
Self::Eager(Gc::new(Vec::new()))
@@ -419,7 +404,8 @@
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Trace)]
+#[trivially_drop]
pub enum Val {
Bool(bool),
Null,
@@ -429,21 +415,6 @@
Obj(ObjValue),
Func(Gc<FuncVal>),
DebugGcTraceValue(DebugGcTraceValue),
-}
-impl Finalize for Val {}
-unsafe impl Trace for Val {
- custom_trace!(this, {
- match &this {
- Val::Bool(_) => {}
- Val::Null => {}
- Val::Str(_) => {}
- Val::Num(_) => {}
- Val::Arr(a) => mark(a),
- Val::Obj(o) => mark(o),
- Val::Func(f) => mark(f),
- Val::DebugGcTraceValue(v) => mark(v),
- }
- });
}
macro_rules! matches_unwrap {
crates/jrsonnet-interner/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-interner/Cargo.toml
+++ b/crates/jrsonnet-interner/Cargo.toml
@@ -9,4 +9,4 @@
[dependencies]
serde = { version = "1.0" }
rustc-hash = "1.1.0"
-gc = { version = "0.4.1", features = ["derive"] }
+jrsonnet-gc = { version = "0.4.2", features = ["derive"] }
crates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-interner/src/lib.rs
+++ b/crates/jrsonnet-interner/src/lib.rs
@@ -1,4 +1,4 @@
-use gc::{unsafe_empty_trace, Finalize, Trace};
+use jrsonnet_gc::{unsafe_empty_trace, Finalize, Trace};
use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
use std::{
crates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-parser/Cargo.toml
+++ b/crates/jrsonnet-parser/Cargo.toml
@@ -18,7 +18,7 @@
unescape = "0.1.0"
serde = { version = "1.0", features = ["derive", "rc"], optional = true }
-gc = { version = "0.4.1", features = ["derive"] }
+jrsonnet-gc = { version = "0.4.2", features = ["derive"] }
[dev-dependencies]
jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.8" }
crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/expr.rs
+++ b/crates/jrsonnet-parser/src/expr.rs
@@ -1,4 +1,4 @@
-use gc::{unsafe_empty_trace, Finalize, Trace};
+use jrsonnet_gc::{unsafe_empty_trace, Finalize, Trace};
use jrsonnet_interner::IStr;
#[cfg(feature = "deserialize")]
use serde::Deserialize;
@@ -13,21 +13,19 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub enum FieldName {
/// {fixed: 2}
Fixed(IStr),
/// {["dyn"+"amic"]: 3}
Dyn(LocExpr),
}
-impl Finalize for FieldName {}
-unsafe impl Trace for FieldName {
- unsafe_empty_trace!();
-}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, Trace)]
+#[trivially_drop]
pub enum Visibility {
/// :
Normal,
@@ -36,10 +34,6 @@
/// :::
Unhide,
}
-impl Finalize for Visibility {}
-unsafe impl Trace for Visibility {
- unsafe_empty_trace!();
-}
impl Visibility {
pub fn is_visible(&self) -> bool {
@@ -49,16 +43,14 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Trace)]
+#[trivially_drop]
pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);
-impl Finalize for AssertStmt {}
-unsafe impl Trace for AssertStmt {
- unsafe_empty_trace!();
-}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub struct FieldMember {
pub name: FieldName,
pub plus: bool,
@@ -66,36 +58,26 @@
pub visibility: Visibility,
pub value: LocExpr,
}
-impl Finalize for FieldMember {}
-unsafe impl Trace for FieldMember {
- unsafe_empty_trace!();
-}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub enum Member {
Field(FieldMember),
BindStmt(BindSpec),
AssertStmt(AssertStmt),
}
-impl Finalize for Member {}
-unsafe impl Trace for Member {
- unsafe_empty_trace!();
-}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, Trace)]
+#[trivially_drop]
pub enum UnaryOpType {
Plus,
Minus,
BitNot,
Not,
-}
-impl Finalize for UnaryOpType {}
-unsafe impl Trace for UnaryOpType {
- unsafe_empty_trace!();
}
impl Display for UnaryOpType {
@@ -116,7 +98,8 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, Trace)]
+#[trivially_drop]
pub enum BinaryOpType {
Mul,
Div,
@@ -145,10 +128,6 @@
And,
Or,
}
-impl Finalize for BinaryOpType {}
-unsafe impl Trace for BinaryOpType {
- unsafe_empty_trace!();
-}
impl Display for BinaryOpType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -183,22 +162,22 @@
/// name, default value
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub struct Param(pub IStr, pub Option<LocExpr>);
-impl Finalize for Param {}
-unsafe impl Trace for Param {
- unsafe_empty_trace!();
-}
/// Defined function parameters
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, Clone, PartialEq)]
pub struct ParamsDesc(pub Rc<Vec<Param>>);
-impl Finalize for ParamsDesc {}
+
+/// Safety:
+/// AST is acyclic, and there should be no gc pointers
unsafe impl Trace for ParamsDesc {
unsafe_empty_trace!();
}
+impl Finalize for ParamsDesc {}
impl Deref for ParamsDesc {
type Target = Vec<Param>;
@@ -209,21 +188,15 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub struct Arg(pub Option<String>, pub LocExpr);
-impl Finalize for Arg {}
-unsafe impl Trace for Arg {
- unsafe_empty_trace!();
-}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub struct ArgsDesc(pub Vec<Arg>);
-impl Finalize for ArgsDesc {}
-unsafe impl Trace for ArgsDesc {
- unsafe_empty_trace!();
-}
impl Deref for ArgsDesc {
type Target = Vec<Arg>;
@@ -234,50 +207,39 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Trace)]
+#[trivially_drop]
pub struct BindSpec {
pub name: IStr,
pub params: Option<ParamsDesc>,
pub value: LocExpr,
-}
-impl Finalize for BindSpec {}
-unsafe impl Trace for BindSpec {
- unsafe_empty_trace!();
}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub struct IfSpecData(pub LocExpr);
-impl Finalize for IfSpecData {}
-unsafe impl Trace for IfSpecData {
- unsafe_empty_trace!();
-}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub struct ForSpecData(pub IStr, pub LocExpr);
-impl Finalize for ForSpecData {}
-unsafe impl Trace for ForSpecData {
- unsafe_empty_trace!();
-}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub enum CompSpec {
IfSpec(IfSpecData),
ForSpec(ForSpecData),
-}
-impl Finalize for CompSpec {}
-unsafe impl Trace for CompSpec {
- unsafe_empty_trace!();
}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub struct ObjComp {
pub pre_locals: Vec<BindSpec>,
pub key: LocExpr,
@@ -285,26 +247,20 @@
pub post_locals: Vec<BindSpec>,
pub compspecs: Vec<CompSpec>,
}
-impl Finalize for ObjComp {}
-unsafe impl Trace for ObjComp {
- unsafe_empty_trace!();
-}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub enum ObjBody {
MemberList(Vec<Member>),
ObjComp(ObjComp),
-}
-impl Finalize for ObjBody {}
-unsafe impl Trace for ObjBody {
- unsafe_empty_trace!();
}
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq, Clone, Copy)]
+#[derive(Debug, PartialEq, Clone, Copy, Trace)]
+#[trivially_drop]
pub enum LiteralType {
This,
Super,
@@ -313,26 +269,20 @@
True,
False,
}
-impl Finalize for LiteralType {}
-unsafe impl Trace for LiteralType {
- unsafe_empty_trace!();
-}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub struct SliceDesc {
pub start: Option<LocExpr>,
pub end: Option<LocExpr>,
pub step: Option<LocExpr>,
-}
-impl Finalize for SliceDesc {}
-unsafe impl Trace for SliceDesc {
- unsafe_empty_trace!();
}
/// Syntax base
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Trace)]
+#[trivially_drop]
pub enum Expr {
Literal(LiteralType),
@@ -396,20 +346,13 @@
cond_else: Option<LocExpr>,
},
}
-impl Finalize for Expr {}
-unsafe impl Trace for Expr {
- unsafe_empty_trace!();
-}
/// file, begin offset, end offset
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Trace)]
+#[trivially_drop]
pub struct ExprLocation(pub Rc<Path>, pub usize, pub usize);
-impl Finalize for ExprLocation {}
-unsafe impl Trace for ExprLocation {
- unsafe_empty_trace!();
-}
impl Debug for ExprLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -422,10 +365,12 @@
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Clone, PartialEq)]
pub struct LocExpr(pub Rc<Expr>, pub Option<ExprLocation>);
-impl Finalize for LocExpr {}
+/// Safety:
+/// AST is acyclic, and there should be no gc pointers
unsafe impl Trace for LocExpr {
unsafe_empty_trace!();
}
+impl Finalize for LocExpr {}
impl Debug for LocExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
crates/jrsonnet-types/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-types/Cargo.toml
+++ b/crates/jrsonnet-types/Cargo.toml
@@ -8,4 +8,4 @@
[dependencies]
peg = "0.7.0"
-gc = { version = "0.4.1", features = ["derive"] }
+jrsonnet-gc = { version = "0.4.2", features = ["derive"] }
crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-types/src/lib.rs
+++ b/crates/jrsonnet-types/src/lib.rs
@@ -1,6 +1,6 @@
#![allow(clippy::redundant_closure_call)]
-use gc::{unsafe_empty_trace, Finalize, Trace};
+use jrsonnet_gc::Trace;
use std::fmt::Display;
#[macro_export]
@@ -78,7 +78,8 @@
);
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]
+#[trivially_drop]
pub enum ValType {
Bool,
Null,
@@ -87,10 +88,6 @@
Arr,
Obj,
Func,
-}
-impl Finalize for ValType {}
-unsafe impl Trace for ValType {
- unsafe_empty_trace!();
}
impl ValType {
@@ -114,7 +111,8 @@
}
}
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Trace)]
+#[trivially_drop]
pub enum ComplexValType {
Any,
Char,
@@ -127,10 +125,6 @@
UnionRef(&'static [ComplexValType]),
Sum(Vec<ComplexValType>),
SumRef(&'static [ComplexValType]),
-}
-impl Finalize for ComplexValType {}
-unsafe impl Trace for ComplexValType {
- unsafe_empty_trace!();
}
impl From<ValType> for ComplexValType {