diff --git a/.trinity/seals/t27o_T27oRust.json b/.trinity/seals/t27o_T27oRust.json index ce1ed15a37..d93e496bb3 100644 --- a/.trinity/seals/t27o_T27oRust.json +++ b/.trinity/seals/t27o_T27oRust.json @@ -2,23 +2,23 @@ "built_by": "t27c-bootstrap@0.5.2+ea35d9b72", "closure": [], "config": "gen=c,rust,verilog,zig;tests=zig", - "gen_hash_c": "sha256:08df0e325d4acb3d37cda78c58f0752a3454fdd64190e33bd7719233129e986a", - "gen_hash_rust": "sha256:ae90e0046b61cf596e6114e14c62abeaed343a834d5131d981058727a54ba933", - "gen_hash_verilog": "sha256:e0f53958647f52ef5b82d57d3553e4bada519d5ce98e78a861d2cbb74bcf1d49", - "gen_hash_zig": "sha256:1d85bad0405fe228eae8ad363edb6fb76b26e9ee87cf7aa0fadac43c49483f4a", + "gen_hash_c": "sha256:ba1f66e21d989982d79ee41c7913ef3937b1a716632e1650c0f552ce56044ff5", + "gen_hash_rust": "sha256:a2cad2a0e3bb75c1df629d761d91debbe7ca34c1bf2a9ed6e720928ff2ced311", + "gen_hash_verilog": "sha256:dfc8a0c23a672fea3f010c7a6a4fa0790565f15d74d245d8824214f53e4595af", + "gen_hash_zig": "sha256:7736f857fb377c908dd4f0dfdd20aeea04ffb6024ce384a19a59a2b5c8bc5770", "module": "T27oRust", "ring": 12, "seal_schema": 2, - "sealed_at": "2026-10-19T02:57:39Z", + "sealed_at": "2026-10-19T03:25:15Z", "sealed_by": "t27c-bootstrap@0.5.2", - "spec_hash": "sha256:11f3aefa0a152d9ca963773018e35b1e39730ac53b25604be67252aaf85522a3", + "spec_hash": "sha256:a0e477ab019f977b889abd108fb797fa82dde39c4d0d594e33e4c86b38fbe935", "spec_path": "specs/tools/t27o/rust_convert.t27", "tests": { "failed": 0, "failing": [], "forced": false, - "passed": 128, - "total": 128, + "passed": 129, + "total": 129, "vacuous": 0 }, "toolchain": { diff --git a/.trinity/seals/t27o_T27oRustStd.json b/.trinity/seals/t27o_T27oRustStd.json index e7402c6cdb..b8ae66010f 100644 --- a/.trinity/seals/t27o_T27oRustStd.json +++ b/.trinity/seals/t27o_T27oRustStd.json @@ -15,23 +15,23 @@ } ], "config": "gen=c,rust,verilog,zig;tests=zig", - "gen_hash_c": "sha256:cef0604f716d2aa7f0a21b5dabb8af9eac42cfd7528bf0aaf5c140fd00723739", - "gen_hash_rust": "sha256:fa9767acc5685bdce7cd03f7d542545c60e718a44f4b75533aac9856dcf2234d", - "gen_hash_verilog": "sha256:6ce3da44fac0d82bcc12c8c522641b21edd45b0ed84abcfc65fb2321bf0b8557", - "gen_hash_zig": "sha256:3a854380824358f5e294a1c9a0e180717706e4b0f89be2b65635b9443b56326e", + "gen_hash_c": "sha256:fe7f38f1687785370d91298f1842a21ae88826238310fafd04bc72e2592c5e6b", + "gen_hash_rust": "sha256:9ddea23180c0817a0c5e97a5a84106175769924cfbd397e658360fdff92302d9", + "gen_hash_verilog": "sha256:1c3f8556c8c801f4201e21b9a593422617eec02069c917cb423ccfa67cf08d2a", + "gen_hash_zig": "sha256:eac278d99fb6df3a70c3f3b5a894ce0347048da5e6f13778b4cc8a4f69c12f16", "module": "T27oRustStd", "ring": 12, "seal_schema": 2, - "sealed_at": "2026-10-19T02:57:25Z", + "sealed_at": "2026-10-19T03:25:06Z", "sealed_by": "t27c-bootstrap@0.5.2", - "spec_hash": "sha256:66a569db8a5e54879d6958aa47e96942e80615d5d5ac5a9b03b8a6222da6e024", + "spec_hash": "sha256:e72606b4b3d7611883db25ed9fdaecb4353fe6a1fef551500b3cd1cc18cceb79", "spec_path": "specs/tools/t27o/rust_std.t27", "tests": { "failed": 0, "failing": [], "forced": false, - "passed": 61, - "total": 61, + "passed": 51, + "total": 51, "vacuous": 0 }, "toolchain": { diff --git a/gen/rust/tools/t27o/rust_convert.rs b/gen/rust/tools/t27o/rust_convert.rs index bd8baf3bc3..5a62697752 100644 --- a/gen/rust/tools/t27o/rust_convert.rs +++ b/gen/rust/tools/t27o/rust_convert.rs @@ -1,6 +1,6 @@ // Generated from .t27 spec // DO NOT EDIT — generated by t27c -// NOT LOWERED BY THIS BACKEND: 128 test(s), 0 invariant(s), 0 function(s) with no body. +// NOT LOWERED BY THIS BACKEND: 129 test(s), 0 invariant(s), 0 function(s) with no body. // This backend emits declarations only. The spec's checks live in // the Zig and Verilog outputs; do not read this file as verified. @@ -302,6 +302,8 @@ pub const R_VECTYPE: usize = 36; pub const R_LIBM: usize = 37; +pub const R_SLICEGEN: usize = 38; + pub const VU_READ: usize = 0; pub const VU_CHANGED: usize = 1; @@ -3419,19 +3421,19 @@ pub const STD_MODS: [&'static str; 5] = ["", "tools::t27o::rust_std", "hosting:: pub const MOD_TTEXT: u8 = 4; -pub const STD_N: usize = 75; +pub const STD_N: usize = 74; -pub const STD_NAME: [&'static str; 75] = ["len", "is_empty", "as_bytes", "as_str", "as_slice", "clone", "abs", "abs", "min", "max", "cmp::min", "cmp::max", "wrapping_add", "wrapping_sub", "wrapping_mul", "checked_add", "checked_sub", "checked_mul", "trim", "trim_start", "trim_end", "starts_with", "ends_with", "contains", "contains", "parse", "iter.sum", "iter.count", "unwrap", "expect", "is_some", "is_none", "is_ok", "is_err", "is_ok", "is_err", "ok", "ok_or", "context", "eq", "is_ascii_alphabetic", "is_ascii_alphanumeric", "is_ascii_digit", "chars", "find", "find", "trim_start_matches", "trim_start_matches", "trim_end_matches", "trim_end_matches", "strip_prefix", "strip_prefix", "strip_suffix", "strip_suffix", "starts_with", "count_ones", "leading_zeros", "trailing_zeros", "pow", "saturating_add", "saturating_sub", "saturating_mul", "div_ceil", "sqrt", "is_finite", "to_bits", "is_ascii", "is_ascii", "is_ascii", "to_ascii_lowercase", "to_ascii_uppercase", "get", "contains", "contains.char", "unwrap_or"]; +pub const STD_NAME: [&'static str; 74] = ["len", "is_empty", "as_bytes", "as_str", "as_slice", "clone", "abs", "abs", "min", "max", "cmp::min", "cmp::max", "wrapping_add", "wrapping_sub", "wrapping_mul", "checked_add", "checked_sub", "checked_mul", "trim", "trim_start", "trim_end", "starts_with", "ends_with", "contains", "contains", "parse", "iter.sum", "iter.count", "unwrap", "expect", "is_some", "is_none", "is_ok", "is_err", "is_ok", "is_err", "ok", "ok_or", "context", "eq", "is_ascii_alphabetic", "is_ascii_alphanumeric", "is_ascii_digit", "chars", "find", "find", "trim_start_matches", "trim_start_matches", "trim_end_matches", "trim_end_matches", "strip_prefix", "strip_prefix", "strip_suffix", "strip_suffix", "starts_with", "count_ones", "leading_zeros", "trailing_zeros", "pow", "saturating_add", "saturating_sub", "saturating_mul", "div_ceil", "sqrt", "is_finite", "to_bits", "is_ascii", "is_ascii", "is_ascii", "to_ascii_lowercase", "to_ascii_uppercase", "get", "contains.char", "unwrap_or"]; -pub const STD_CLASS: [u8; 75] = [0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 3, 4, 4, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 4, 2, 2, 2, 4, 4, 3, 0]; +pub const STD_CLASS: [u8; 74] = [0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 3, 4, 4, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 4, 2, 2, 2, 4, 3, 0]; -pub const STD_ARGS: [u8; 75] = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]; +pub const STD_ARGS: [u8; 74] = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]; -pub const STD_FORM: [&'static str; 75] = ["#.len", "(#.len == 0)", "#", "#", "#", "#", "@abs(#)", "rust_std::abs_%(#)", "@min(#, $)", "@max(#, $)", "@min(#)", "@max(#)", "(# +% $)", "(# -% $)", "(# *% $)", "rust_std::checked_add_%(#, $)", "rust_std::checked_sub_%(#, $)", "rust_std::checked_mul_%(#, $)", "#[type_text::trim_lo(#, 0, #.len) .. type_text::trim_hi(#, type_text::trim_lo(#, 0, #.len), #.len)]", "#[type_text::trim_lo(#, 0, #.len) .. #.len]", "#[0 .. type_text::trim_hi(#, 0, #.len)]", "toolchain::starts_with(#, $)", "toolchain::ends_with(#, $t)", "rust_std::str_contains(#, $t)", "rust_std::bytes_contain(#, $)", "rust_std::parse_%(#)", "rust_std::sum_%(#)", "#.len", "#.?", "#.?", "(# != null)", "(# == null)", "#", "(# == false)", "(# != null)", "(# == null)", "#", "#", "#", "type_text::same(#, $)", "type_text::alpha(#)", "rust_std::alnum(#)", "type_text::digit(#)", "#", "rust_std::find_text(#, $)", "rust_std::find_byte(#, $)", "rust_std::trim_start_matches_text(#, $)", "rust_std::trim_start_matches_byte(#, $)", "rust_std::trim_end_matches_text(#, $)", "rust_std::trim_end_matches_byte(#, $)", "rust_std::strip_prefix_text(#, $)", "rust_std::strip_prefix_byte(#, $)", "rust_std::strip_suffix_text(#, $)", "rust_std::strip_suffix_byte(#, $)", "rust_std::starts_with_byte(#, $)", "rust_std::count_ones_%(#)", "rust_std::leading_zeros_%(#)", "rust_std::trailing_zeros_%(#)", "rust_std::pow_%(#, $)", "rust_std::saturating_add_%(#, $)", "rust_std::saturating_sub_%(#, $)", "rust_std::saturating_mul_%(#, $)", "rust_std::div_ceil_%(#, $)", "@sqrt(#)", "rust_std::is_finite_%(#)", "rust_std::to_bits_%(#)", "rust_std::is_ascii_text(#)", "rust_std::is_ascii_text(#)", "rust_std::is_ascii_%(#)", "rust_std::to_ascii_lowercase_%(#)", "rust_std::to_ascii_uppercase_%(#)", "rust_std::get_%(#, $)", "rust_std::contains_%(#, $)", "rust_std::str_contains_char(#, $)", "if (# != null) { ^.? } else { $ }"]; +pub const STD_FORM: [&'static str; 74] = ["#.len", "(#.len == 0)", "#", "#", "#", "#", "@abs(#)", "rust_std::abs_%(#)", "@min(#, $)", "@max(#, $)", "@min(#)", "@max(#)", "(# +% $)", "(# -% $)", "(# *% $)", "rust_std::checked_add_%(#, $)", "rust_std::checked_sub_%(#, $)", "rust_std::checked_mul_%(#, $)", "#[type_text::trim_lo(#, 0, #.len) .. type_text::trim_hi(#, type_text::trim_lo(#, 0, #.len), #.len)]", "#[type_text::trim_lo(#, 0, #.len) .. #.len]", "#[0 .. type_text::trim_hi(#, 0, #.len)]", "toolchain::starts_with(#, $)", "toolchain::ends_with(#, $t)", "rust_std::str_contains(#, $t)", "rust_std::bytes_contain(#, $)", "rust_std::parse_%(#)", "rust_std::sum_%(#)", "#.len", "#.?", "#.?", "(# != null)", "(# == null)", "#", "(# == false)", "(# != null)", "(# == null)", "#", "#", "#", "type_text::same(#, $)", "type_text::alpha(#)", "rust_std::alnum(#)", "type_text::digit(#)", "#", "rust_std::find_text(#, $)", "rust_std::find_byte(#, $)", "rust_std::trim_start_matches_text(#, $)", "rust_std::trim_start_matches_byte(#, $)", "rust_std::trim_end_matches_text(#, $)", "rust_std::trim_end_matches_byte(#, $)", "rust_std::strip_prefix_text(#, $)", "rust_std::strip_prefix_byte(#, $)", "rust_std::strip_suffix_text(#, $)", "rust_std::strip_suffix_byte(#, $)", "rust_std::starts_with_byte(#, $)", "rust_std::count_ones_%(#)", "rust_std::leading_zeros_%(#)", "rust_std::trailing_zeros_%(#)", "rust_std::pow_%(#, $)", "rust_std::saturating_add_%(#, $)", "rust_std::saturating_sub_%(#, $)", "rust_std::saturating_mul_%(#, $)", "rust_std::div_ceil_%(#, $)", "@sqrt(#)", "rust_std::is_finite_%(#)", "rust_std::to_bits_%(#)", "rust_std::is_ascii_text(#)", "rust_std::is_ascii_text(#)", "rust_std::is_ascii_%(#)", "rust_std::to_ascii_lowercase_%(#)", "rust_std::to_ascii_uppercase_%(#)", "rust_std::get_%(#, $)", "rust_std::str_contains_char(#, $)", "if (# != null) { ^.? } else { $ }"]; -pub const STD_TYPES: [&'static str; 75] = ["", "", "", "", "", "", "", " i8 i16 i32 i64 ", "", "", "", "", "", "", "", " u32 u64 usize i32 i64 ", " u32 u64 usize i32 i64 ", " u32 u64 usize i32 i64 ", "", "", "", "", "", "", " u8 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u32 u64 usize i32 i64 f32 f64 ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize ", "", " f32 f64 ", " f32 f64 ", "", " u8 ", " u8 ", " u8 ", " u8 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 f32 f64 ", " u16 u32 u64 usize i8 i16 i32 i64 f32 f64 ", "", ""]; +pub const STD_TYPES: [&'static str; 74] = ["", "", "", "", "", "", "", " i8 i16 i32 i64 ", "", "", "", "", "", "", "", " u32 u64 usize i32 i64 ", " u32 u64 usize i32 i64 ", " u32 u64 usize i32 i64 ", "", "", "", "", "", "", " u8 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u32 u64 usize i32 i64 f32 f64 ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize ", "", " f32 f64 ", " f32 f64 ", "", " u8 ", " u8 ", " u8 ", " u8 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 f32 f64 ", "", ""]; -pub const STD_USE: [u8; 75] = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 4, 4, 4, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 1, 4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]; +pub const STD_USE: [u8; 74] = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 4, 4, 4, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 1, 4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]; pub fn listed(w: &'static str, t: &[u8]) -> bool { if (t.len() == 0) { @@ -3981,6 +3983,10 @@ pub fn method(src: &[u8], st: &mut [usize], out: &mut [u8], start: usize, ra: us refuse(st, R_LIBM, ka, ka, kb); return (); } + if ((word_is(src, na, nb, b"contains") && (cls == C_SLICE)) && listed(" u16 u32 u64 usize i8 i16 i32 i64 f32 f64 ", &src[(tyl) as usize..(tyh) as usize])) { + refuse(st, R_SLICEGEN, ka, tyl, tyh); + return (); + } refuse(st, R_METHOD, ka, ka, kb); return (); } @@ -6946,10 +6952,14 @@ pub fn put_reason(src: &[u8], st: &mut [usize], out: &mut [u8]) -> () { if (c == R_LIBM) { puts(st, out, b"libm function not bit-exact"); } else { - if (c == R_SPLICE) { - puts(st, out, b"a used module's own use t27c does not splice (its type_text:: names stay unresolved, the gap specs/compiler/int_type_names.t27 records)"); + if (c == R_SLICEGEN) { + puts(st, out, b"slice contains on"); } else { - puts(st, out, b"syntax"); + if (c == R_SPLICE) { + puts(st, out, b"a used module's own use t27c does not splice (its type_text:: names stay unresolved, the gap specs/compiler/int_type_names.t27 records)"); + } else { + puts(st, out, b"syntax"); + } } } } @@ -6991,6 +7001,9 @@ pub fn put_reason(src: &[u8], st: &mut [usize], out: &mut [u8]) -> () { puts(st, out, b"` at line "); let at_line: usize = line_at(src, st, st[(AT) as usize]); put_num(st, out, at_line); + if (c == R_SLICEGEN) { + puts(st, out, b": no generic helper, and per-type copies are refused by the DRY ratchet"); + } } pub fn put_refusal(src: &[u8], st: &mut [usize], out: &mut [u8], what: &[u8], na: usize, nb: usize, pos: usize) -> () { diff --git a/specs/tools/t27o/rust_convert.t27 b/specs/tools/t27o/rust_convert.t27 index 9c56619878..a6258ab3d2 100644 --- a/specs/tools/t27o/rust_convert.t27 +++ b/specs/tools/t27o/rust_convert.t27 @@ -323,6 +323,9 @@ pub const R_VECMOVE : usize = 35; pub const R_VECTYPE : usize = 36; /// A float function Rust gets from the platform's libm: its last bit is the library's, not IEEE 754's. pub const R_LIBM : usize = 37; +/// A slice `contains` on a scalar other than u8: bytes_contain is the one body, t27 has no generics to share it, +/// and a copy per element type is refused by the duplicate-bodies ratchet (tools/dupe_scan.py). +pub const R_SLICEGEN : usize = 38; /// How a fn uses a vec! local: VU_READ only reads it, VU_CHANGED changes it, VU_MOVED hands it on. pub const VU_READ : usize = 0; pub const VU_CHANGED : usize = 1; @@ -2989,10 +2992,13 @@ pub fn let_int(src: []const u8, st: []usize, d: usize) -> usize { // pow, saturating_add / sub / mul and div_ceil (unsigned) name _ for the receiver's integer type; sqrt is // the builtin; is_finite and to_bits name _ of f32 / f64 (to_bits is an @bitCast that gen-rust prints // as written); is_ascii, to_ascii_lowercase and to_ascii_uppercase map on a u8 and (is_ascii) on a text or a byte -// slice; get(i) and contains(&x) map on a slice of scalars; unwrap_or is an `if` where it stands alone as a value. +// slice; get(i) maps on a slice of scalars, contains(&x) on a slice of u8 only (bytes_contain); unwrap_or is an `if` where +// it stands alone as a value. // Refused, each for a reason: `ln` (R_LIBM: the platform libm's last bit is not IEEE 754's), a text's or a char's // to_ascii_lowercase (an owned String; no char class), the signed div_ceil (unstable in Rust), a get with a -// range, and an unwrap_or inside an expression or on a receiver that calls a fn of the file. +// range, a contains on a slice of any other scalar (R_SLICEGEN: no generics to share bytes_contain, and a copy per +// type is refused by the duplicate-bodies ratchet), and an unwrap_or inside an expression or on a receiver that +// calls a fn of the file. /// The receiver classes an entry asks for. pub const C_ANY : u8 = 0; @@ -3019,16 +3025,16 @@ pub const CK_INDEX : usize = 8; pub const STD_MODS : [5]str = ["", "tools::t27o::rust_std", "hosting::toolchain", "tri::mutate::plant", "tri::t27b::type_text"]; pub const MOD_TTEXT : u8 = 4; -pub const STD_N : usize = 75; +pub const STD_N : usize = 74; /// The Rust method (`iter.sum` is `.iter().sum()`, `cmp::max` a path call). -pub const STD_NAME : [75]str = ["len", "is_empty", "as_bytes", "as_str", "as_slice", "clone", "abs", "abs", "min", "max", "cmp::min", "cmp::max", "wrapping_add", "wrapping_sub", "wrapping_mul", "checked_add", "checked_sub", "checked_mul", "trim", "trim_start", "trim_end", "starts_with", "ends_with", "contains", "contains", "parse", "iter.sum", "iter.count", "unwrap", "expect", "is_some", "is_none", "is_ok", "is_err", "is_ok", "is_err", "ok", "ok_or", "context", "eq", "is_ascii_alphabetic", "is_ascii_alphanumeric", "is_ascii_digit", "chars", "find", "find", "trim_start_matches", "trim_start_matches", "trim_end_matches", "trim_end_matches", "strip_prefix", "strip_prefix", "strip_suffix", "strip_suffix", "starts_with", "count_ones", "leading_zeros", "trailing_zeros", "pow", "saturating_add", "saturating_sub", "saturating_mul", "div_ceil", "sqrt", "is_finite", "to_bits", "is_ascii", "is_ascii", "is_ascii", "to_ascii_lowercase", "to_ascii_uppercase", "get", "contains", "contains.char", "unwrap_or"]; -pub const STD_CLASS : [75]u8 = [0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 3, 4, 4, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 4, 2, 2, 2, 4, 4, 3, 0]; +pub const STD_NAME : [74]str = ["len", "is_empty", "as_bytes", "as_str", "as_slice", "clone", "abs", "abs", "min", "max", "cmp::min", "cmp::max", "wrapping_add", "wrapping_sub", "wrapping_mul", "checked_add", "checked_sub", "checked_mul", "trim", "trim_start", "trim_end", "starts_with", "ends_with", "contains", "contains", "parse", "iter.sum", "iter.count", "unwrap", "expect", "is_some", "is_none", "is_ok", "is_err", "is_ok", "is_err", "ok", "ok_or", "context", "eq", "is_ascii_alphabetic", "is_ascii_alphanumeric", "is_ascii_digit", "chars", "find", "find", "trim_start_matches", "trim_start_matches", "trim_end_matches", "trim_end_matches", "strip_prefix", "strip_prefix", "strip_suffix", "strip_suffix", "starts_with", "count_ones", "leading_zeros", "trailing_zeros", "pow", "saturating_add", "saturating_sub", "saturating_mul", "div_ceil", "sqrt", "is_finite", "to_bits", "is_ascii", "is_ascii", "is_ascii", "to_ascii_lowercase", "to_ascii_uppercase", "get", "contains.char", "unwrap_or"]; +pub const STD_CLASS : [74]u8 = [0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 3, 4, 4, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 4, 2, 2, 2, 4, 3, 0]; /// How many arguments the method takes. -pub const STD_ARGS : [75]u8 = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]; -pub const STD_FORM : [75]str = ["#.len", "(#.len == 0)", "#", "#", "#", "#", "@abs(#)", "rust_std::abs_%(#)", "@min(#, $)", "@max(#, $)", "@min(#)", "@max(#)", "(# +% $)", "(# -% $)", "(# *% $)", "rust_std::checked_add_%(#, $)", "rust_std::checked_sub_%(#, $)", "rust_std::checked_mul_%(#, $)", "#[type_text::trim_lo(#, 0, #.len) .. type_text::trim_hi(#, type_text::trim_lo(#, 0, #.len), #.len)]", "#[type_text::trim_lo(#, 0, #.len) .. #.len]", "#[0 .. type_text::trim_hi(#, 0, #.len)]", "toolchain::starts_with(#, $)", "toolchain::ends_with(#, $t)", "rust_std::str_contains(#, $t)", "rust_std::bytes_contain(#, $)", "rust_std::parse_%(#)", "rust_std::sum_%(#)", "#.len", "#.?", "#.?", "(# != null)", "(# == null)", "#", "(# == false)", "(# != null)", "(# == null)", "#", "#", "#", "type_text::same(#, $)", "type_text::alpha(#)", "rust_std::alnum(#)", "type_text::digit(#)", "#", "rust_std::find_text(#, $)", "rust_std::find_byte(#, $)", "rust_std::trim_start_matches_text(#, $)", "rust_std::trim_start_matches_byte(#, $)", "rust_std::trim_end_matches_text(#, $)", "rust_std::trim_end_matches_byte(#, $)", "rust_std::strip_prefix_text(#, $)", "rust_std::strip_prefix_byte(#, $)", "rust_std::strip_suffix_text(#, $)", "rust_std::strip_suffix_byte(#, $)", "rust_std::starts_with_byte(#, $)", "rust_std::count_ones_%(#)", "rust_std::leading_zeros_%(#)", "rust_std::trailing_zeros_%(#)", "rust_std::pow_%(#, $)", "rust_std::saturating_add_%(#, $)", "rust_std::saturating_sub_%(#, $)", "rust_std::saturating_mul_%(#, $)", "rust_std::div_ceil_%(#, $)", "@sqrt(#)", "rust_std::is_finite_%(#)", "rust_std::to_bits_%(#)", "rust_std::is_ascii_text(#)", "rust_std::is_ascii_text(#)", "rust_std::is_ascii_%(#)", "rust_std::to_ascii_lowercase_%(#)", "rust_std::to_ascii_uppercase_%(#)", "rust_std::get_%(#, $)", "rust_std::contains_%(#, $)", "rust_std::str_contains_char(#, $)", "if (# != null) { ^.? } else { $ }"]; +pub const STD_ARGS : [74]u8 = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]; +pub const STD_FORM : [74]str = ["#.len", "(#.len == 0)", "#", "#", "#", "#", "@abs(#)", "rust_std::abs_%(#)", "@min(#, $)", "@max(#, $)", "@min(#)", "@max(#)", "(# +% $)", "(# -% $)", "(# *% $)", "rust_std::checked_add_%(#, $)", "rust_std::checked_sub_%(#, $)", "rust_std::checked_mul_%(#, $)", "#[type_text::trim_lo(#, 0, #.len) .. type_text::trim_hi(#, type_text::trim_lo(#, 0, #.len), #.len)]", "#[type_text::trim_lo(#, 0, #.len) .. #.len]", "#[0 .. type_text::trim_hi(#, 0, #.len)]", "toolchain::starts_with(#, $)", "toolchain::ends_with(#, $t)", "rust_std::str_contains(#, $t)", "rust_std::bytes_contain(#, $)", "rust_std::parse_%(#)", "rust_std::sum_%(#)", "#.len", "#.?", "#.?", "(# != null)", "(# == null)", "#", "(# == false)", "(# != null)", "(# == null)", "#", "#", "#", "type_text::same(#, $)", "type_text::alpha(#)", "rust_std::alnum(#)", "type_text::digit(#)", "#", "rust_std::find_text(#, $)", "rust_std::find_byte(#, $)", "rust_std::trim_start_matches_text(#, $)", "rust_std::trim_start_matches_byte(#, $)", "rust_std::trim_end_matches_text(#, $)", "rust_std::trim_end_matches_byte(#, $)", "rust_std::strip_prefix_text(#, $)", "rust_std::strip_prefix_byte(#, $)", "rust_std::strip_suffix_text(#, $)", "rust_std::strip_suffix_byte(#, $)", "rust_std::starts_with_byte(#, $)", "rust_std::count_ones_%(#)", "rust_std::leading_zeros_%(#)", "rust_std::trailing_zeros_%(#)", "rust_std::pow_%(#, $)", "rust_std::saturating_add_%(#, $)", "rust_std::saturating_sub_%(#, $)", "rust_std::saturating_mul_%(#, $)", "rust_std::div_ceil_%(#, $)", "@sqrt(#)", "rust_std::is_finite_%(#)", "rust_std::to_bits_%(#)", "rust_std::is_ascii_text(#)", "rust_std::is_ascii_text(#)", "rust_std::is_ascii_%(#)", "rust_std::to_ascii_lowercase_%(#)", "rust_std::to_ascii_uppercase_%(#)", "rust_std::get_%(#, $)", "rust_std::str_contains_char(#, $)", "if (# != null) { ^.? } else { $ }"]; /// The types `%` may be, space-separated; empty when the template has no `%`. -pub const STD_TYPES : [75]str = ["", "", "", "", "", "", "", " i8 i16 i32 i64 ", "", "", "", "", "", "", "", " u32 u64 usize i32 i64 ", " u32 u64 usize i32 i64 ", " u32 u64 usize i32 i64 ", "", "", "", "", "", "", " u8 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u32 u64 usize i32 i64 f32 f64 ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize ", "", " f32 f64 ", " f32 f64 ", "", " u8 ", " u8 ", " u8 ", " u8 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 f32 f64 ", " u16 u32 u64 usize i8 i16 i32 i64 f32 f64 ", "", ""]; -pub const STD_USE : [75]u8 = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 4, 4, 4, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 1, 4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]; +pub const STD_TYPES : [74]str = ["", "", "", "", "", "", "", " i8 i16 i32 i64 ", "", "", "", "", "", "", "", " u32 u64 usize i32 i64 ", " u32 u64 usize i32 i64 ", " u32 u64 usize i32 i64 ", "", "", "", "", "", "", " u8 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u32 u64 usize i32 i64 f32 f64 ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 ", " u8 u16 u32 u64 usize ", "", " f32 f64 ", " f32 f64 ", "", " u8 ", " u8 ", " u8 ", " u8 ", " u8 u16 u32 u64 usize i8 i16 i32 i64 f32 f64 ", "", ""]; +pub const STD_USE : [74]u8 = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 4, 4, 4, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 1, 4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]; /// Is t a word of the space-separated list w (" u32 u64 ")? pub fn listed(w: str, t: []const u8) -> bool { @@ -3508,6 +3514,11 @@ pub fn method(src: []const u8, st: []usize, out: []u8, start: usize, ra: usize, refuse(st, R_LIBM, ka, ka, kb); return; } + // a slice of any scalar but u8: the one body is bytes_contain, and t27 has no generics to share it + if (word_is(src, na, nb, "contains") and cls == C_SLICE and listed(" u16 u32 u64 usize i8 i16 i32 i64 f32 f64 ", src[tyl .. tyh])) { + refuse(st, R_SLICEGEN, ka, tyl, tyh); + return; + } refuse(st, R_METHOD, ka, ka, kb); return; } @@ -6120,6 +6131,8 @@ pub fn put_reason(src: []const u8, st: []usize, out: []u8) -> void { puts(st, out, "a vec! whose element type or length t27o cannot tell"); } else if (c == R_LIBM) { puts(st, out, "libm function not bit-exact"); + } else if (c == R_SLICEGEN) { + puts(st, out, "slice contains on"); } else if (c == R_SPLICE) { puts(st, out, "a used module's own use t27c does not splice (its type_text:: names stay unresolved, the gap specs/compiler/int_type_names.t27 records)"); } else { @@ -6130,6 +6143,7 @@ pub fn put_reason(src: []const u8, st: []usize, out: []u8) -> void { puts(st, out, "` at line "); const at_line : usize = line_at(src, st, st[AT]); put_num(st, out, at_line); + if (c == R_SLICEGEN) { puts(st, out, ": no generic helper, and per-type copies are refused by the DRY ratchet"); } } /// The comment that stands where a refused item was. @@ -10492,14 +10506,24 @@ test negative_control_get_with_a_range_or_on_a_text_stays_refused { assert(st[NOK] == 0); } -/// contains (#10764) on a slice of any scalar type is contains_ (bytes_contain for u8). A text's contains with a char held in a -/// variable takes str_contains_char (the char is a u32, not the one-byte text a literal is); a char literal still takes str_contains. -test std_contains_of_scalars_and_of_a_char_variable_go_through_the_table { +/// contains (#10764): a slice of u8 is bytes_contain (the one body; t27 has no generics to share it). A text's contains with a char +/// held in a variable takes str_contains_char (the char is a u32, not the one-byte text a literal is); a char literal still takes str_contains. +test std_contains_of_u8_slices_and_of_a_char_variable_go_through_the_table { var out : [2048]u8 = undefined; var st : [1024]usize = [0] ** 1024; - const n : usize = body("fn b(v: &[u32], x: u32) -> bool { v.contains(&x) }\nfn c(s: &str, ch: char) -> bool { s.contains(ch) }\nfn d(s: &str) -> bool { s.contains('x') }\nfn g(v: &Vec, x: u16) -> bool { v.contains(&x) }\nfn k(v: &[f64], x: f64) -> bool { v.contains(&x) }\nfn m(v: &[u8; 4], x: u8) -> bool { v.contains(&x) }", &out, &st); - assert(out_is(n, &out, 0, "use tools::t27o::rust_std;\n\nfn b(v: []const u32, x: u32) -> bool {\n return rust_std::contains_u32(v, x);\n}\n\nfn c(s: []const u8, ch: u32) -> bool {\n return rust_std::str_contains_char(s, ch);\n}\n\nfn d(s: []const u8) -> bool {\n return rust_std::str_contains(s, \"x\");\n}\n\nfn g(v: []const u16, x: u16) -> bool {\n return rust_std::contains_u16(v, x);\n}\n\nfn k(v: []const f64, x: f64) -> bool {\n return rust_std::contains_f64(v, x);\n}\n\nfn m(v: []const u8, x: u8) -> bool {\n return rust_std::bytes_contain(v, x);\n}\n\n")); - assert(st[NOK] == 6); + const n : usize = body("fn c(s: &str, ch: char) -> bool { s.contains(ch) }\nfn d(s: &str) -> bool { s.contains('x') }\nfn f(v: &[u8], x: u8) -> bool { v.contains(&x) }\nfn m(v: &[u8; 4], x: u8) -> bool { v.contains(&x) }", &out, &st); + assert(out_is(n, &out, 0, "use tools::t27o::rust_std;\n\nfn c(s: []const u8, ch: u32) -> bool {\n return rust_std::str_contains_char(s, ch);\n}\n\nfn d(s: []const u8) -> bool {\n return rust_std::str_contains(s, \"x\");\n}\n\nfn f(v: []const u8, x: u8) -> bool {\n return rust_std::bytes_contain(v, x);\n}\n\nfn m(v: []const u8, x: u8) -> bool {\n return rust_std::bytes_contain(v, x);\n}\n\n")); + assert(st[NOK] == 4); +} + +/// Any scalar slice but u8 is refused with R_SLICEGEN: bytes_contain is the one body, and a copy per element type is refused by the +/// duplicate-bodies ratchet (tools/dupe_scan.py), so the converter does not ask rust_std for one. +test negative_control_contains_on_a_u32_slice_is_refused_with_the_dry_reason { + var out : [2048]u8 = undefined; + var st : [1024]usize = [0] ** 1024; + const n : usize = body("fn b(v: &[u32], x: u32) -> bool { v.contains(&x) }\nfn g(v: &Vec, x: u16) -> bool { v.contains(&x) }\nfn k(v: &[f64], x: f64) -> bool { v.contains(&x) }", &out, &st); + assert(out_is(n, &out, 0, "// t27o: refused fn b (line 1): slice contains on `u32` at line 1: no generic helper, and per-type copies are refused by the DRY ratchet\n\nfn b(v: []const u32, x: u32) -> bool {\n}\n\n// t27o: refused fn g (line 2): slice contains on `u16` at line 2: no generic helper, and per-type copies are refused by the DRY ratchet\n\nfn g(v: []const u16, x: u16) -> bool {\n}\n\n// t27o: refused fn k (line 3): slice contains on `f64` at line 3: no generic helper, and per-type copies are refused by the DRY ratchet\n\nfn k(v: []const f64, x: f64) -> bool {\n}\n\n")); + assert(st[NOK] == 0); } /// t27 holds no slice of slices: a slice of texts has no row (a constant array is unrolled instead). diff --git a/specs/tools/t27o/rust_std.t27 b/specs/tools/t27o/rust_std.t27 index 651c7efd0a..b68b2cd467 100644 --- a/specs/tools/t27o/rust_std.t27 +++ b/specs/tools/t27o/rust_std.t27 @@ -29,8 +29,9 @@ ; count_ones_ / leading_zeros_ / trailing_zeros_, u32 ; (#10764) std_bit_counts_are_rusts ; saturating_add / sub / mul (the same nine types) saturating__; hosting::panel has the u64 add, a -; `use` of it splices 28 modules (#7176) so it is written here -; (#10764) std_saturating_arithmetic_of__is_rusts +; `use` of it splices 28 modules (#7176) and a copy of its body is +; refused by the duplicate-bodies ratchet, so the u64 add is built on +; checked_add_u64 (#10764) std_saturating_arithmetic_of__is_rusts ; div_ceil (u8 u16 u32 u64 usize) div_ceil_; a zero divisor traps as Rust's panics; the signed ; div_ceil is unstable in Rust (#10764) std_div_ceil_of__is_rusts ; sqrt (f32, f64) `@sqrt` (IEEE 754 square root, correctly rounded) @@ -43,9 +44,10 @@ ; to_ascii_lowercase / uppercase (u8) to_ascii_lowercase_u8 / _uppercase_u8 (a text's returns an owned ; String and t27o has no char class: both stay refused) (#10764) ; get(i) on a slice of scalars (u8 .. i64, usize, f32, f64) get_, ?T (#10764) std_get_of__is_rusts -; contains(&x) on a slice of u16 .. i64, usize, f32, f64 contains_ (u8 is bytes_contain) +; contains(&x) on a slice bytes_contain for u8 only: t27 has no generics and a per-type copy of +; its body is refused by the duplicate-bodies ratchet, so any other +; element type is refused (R_SLICEGEN in rust_convert.t27) ; contains(c) on a text, c a char in a variable str_contains_char: the char's UTF-8 bytes (#10764) -; std_contains_of__is_rusts, ; std_contains_of_a_char_is_rusts ; unwrap_or(d) on an Option or a Result `if (r != null) { r.? } else { d }` -- t27 has no `orelse`; the ; receiver is written twice (a pure std helper only) and the form @@ -798,13 +800,14 @@ pub fn pow_i64(x: i64, e: u32) -> i64 { // ---------------------------------------------------------------- saturating arithmetic -/// u64::saturating_add: a + b, or the largest u64 when that does not fit. hosting::panel has this fn -/// too, but a `use` of it splices 28 modules into the converted spec (#7176), so it is written here, -/// once, with the rest of the family. The unsigned types narrower than 64 bits add and multiply in -/// u64 and clamp; usize is the 64-bit host's. +/// u64::saturating_add: a + b, or the largest u64 when that does not fit. hosting::panel has this fn too, +/// but a `use` of it splices 28 modules into the converted spec (#7176) and a copy of its body is refused +/// by the duplicate-bodies ratchet, so this one is built on the module's own checked_add_u64. The +/// unsigned types narrower than 64 bits add and multiply in u64 and clamp; usize is the 64-bit host's. pub fn saturating_add_u64(a: u64, b: u64) -> u64 { - if (b > 18446744073709551615 - a) { return 18446744073709551615; } - return a + b; + const s : ?u64 = checked_add_u64(a, b); + if (s == null) { return 18446744073709551615; } + return s.?; } pub fn saturating_sub_u64(a: u64, b: u64) -> u64 { @@ -1138,99 +1141,7 @@ pub fn get_f64(xs: []const f64, i: usize) -> ?f64 { return v; } -// ---------------------------------------------------------------- slice contains - -/// [T]::contains(&x) for a scalar T: some element is `==` x, so a NaN is never contained and -0.0 is 0.0. -/// (The u8 slice is bytes_contain, above.) -pub fn contains_u16(xs: []const u16, x: u16) -> bool { - var i : usize = 0; - while (i < xs.len) { - if (xs[i] == x) { return true; } - i += 1; - } - return false; -} - -pub fn contains_u32(xs: []const u32, x: u32) -> bool { - var i : usize = 0; - while (i < xs.len) { - if (xs[i] == x) { return true; } - i += 1; - } - return false; -} - -pub fn contains_u64(xs: []const u64, x: u64) -> bool { - var i : usize = 0; - while (i < xs.len) { - if (xs[i] == x) { return true; } - i += 1; - } - return false; -} - -pub fn contains_usize(xs: []const usize, x: usize) -> bool { - var i : usize = 0; - while (i < xs.len) { - if (xs[i] == x) { return true; } - i += 1; - } - return false; -} - -pub fn contains_i8(xs: []const i8, x: i8) -> bool { - var i : usize = 0; - while (i < xs.len) { - if (xs[i] == x) { return true; } - i += 1; - } - return false; -} - -pub fn contains_i16(xs: []const i16, x: i16) -> bool { - var i : usize = 0; - while (i < xs.len) { - if (xs[i] == x) { return true; } - i += 1; - } - return false; -} - -pub fn contains_i32(xs: []const i32, x: i32) -> bool { - var i : usize = 0; - while (i < xs.len) { - if (xs[i] == x) { return true; } - i += 1; - } - return false; -} - -pub fn contains_i64(xs: []const i64, x: i64) -> bool { - var i : usize = 0; - while (i < xs.len) { - if (xs[i] == x) { return true; } - i += 1; - } - return false; -} - -pub fn contains_f32(xs: []const f32, x: f32) -> bool { - var i : usize = 0; - while (i < xs.len) { - if (xs[i] == x) { return true; } - i += 1; - } - return false; -} - -pub fn contains_f64(xs: []const f64, x: f64) -> bool { - var i : usize = 0; - while (i < xs.len) { - if (xs[i] == x) { return true; } - i += 1; - } - return false; -} +// ---------------------------------------------------------------- str contains with a char /// str::contains with a char held in a variable (t27o holds a char as its u32 scalar value): the char's UTF-8 /// bytes occur in s. A char literal needle never gets here, it is written as the one-byte text it is. @@ -5297,162 +5208,6 @@ test std_get_of_f64_is_rusts { assert(get_f64(a[0 .. 0], 0) == null); } -/// [u16]::contains(&x): every expected value was printed by rustc 1.99 running `a.contains(&x)` on the same array, for a -/// member (first, middle, last), a non-member and the neighbours of the edge values; the empty slice contains nothing. -test std_contains_of_u16_is_rusts { - const a : [4]u16 = [7, 0, 65535, 300]; - assert(contains_u16(a[0 .. 4], 7) == true); - assert(contains_u16(a[0 .. 4], 0) == true); - assert(contains_u16(a[0 .. 4], 65535) == true); - assert(contains_u16(a[0 .. 4], 300) == true); - assert(contains_u16(a[0 .. 4], 1) == false); - assert(contains_u16(a[0 .. 4], 299) == false); - assert(contains_u16(a[0 .. 4], 301) == false); - assert(contains_u16(a[0 .. 4], 32768) == false); - assert(contains_u16(a[0 .. 0], 7) == false); -} - -/// [u32]::contains(&x): every expected value was printed by rustc 1.99 running `a.contains(&x)` on the same array, for a -/// member (first, middle, last), a non-member and the neighbours of the edge values; the empty slice contains nothing. -test std_contains_of_u32_is_rusts { - const a : [4]u32 = [7, 0, 4294967295, 65536]; - assert(contains_u32(a[0 .. 4], 7) == true); - assert(contains_u32(a[0 .. 4], 0) == true); - assert(contains_u32(a[0 .. 4], 4294967295) == true); - assert(contains_u32(a[0 .. 4], 65536) == true); - assert(contains_u32(a[0 .. 4], 1) == false); - assert(contains_u32(a[0 .. 4], 65535) == false); - assert(contains_u32(a[0 .. 4], 65537) == false); - assert(contains_u32(a[0 .. 4], 2147483648) == false); - assert(contains_u32(a[0 .. 0], 7) == false); -} - -/// [u64]::contains(&x): every expected value was printed by rustc 1.99 running `a.contains(&x)` on the same array, for a -/// member (first, middle, last), a non-member and the neighbours of the edge values; the empty slice contains nothing. -test std_contains_of_u64_is_rusts { - const a : [4]u64 = [7, 0, 18446744073709551615, 4294967296]; - assert(contains_u64(a[0 .. 4], 7) == true); - assert(contains_u64(a[0 .. 4], 0) == true); - assert(contains_u64(a[0 .. 4], 18446744073709551615) == true); - assert(contains_u64(a[0 .. 4], 4294967296) == true); - assert(contains_u64(a[0 .. 4], 1) == false); - assert(contains_u64(a[0 .. 4], 4294967295) == false); - assert(contains_u64(a[0 .. 4], 4294967297) == false); - assert(contains_u64(a[0 .. 4], 9223372036854775808) == false); - assert(contains_u64(a[0 .. 0], 7) == false); -} - -/// [usize]::contains(&x): every expected value was printed by rustc 1.99 running `a.contains(&x)` on the same array, for a -/// member (first, middle, last), a non-member and the neighbours of the edge values; the empty slice contains nothing. -test std_contains_of_usize_is_rusts { - const a : [4]usize = [7, 0, 18446744073709551615, 4294967296]; - assert(contains_usize(a[0 .. 4], 7) == true); - assert(contains_usize(a[0 .. 4], 0) == true); - assert(contains_usize(a[0 .. 4], 18446744073709551615) == true); - assert(contains_usize(a[0 .. 4], 4294967296) == true); - assert(contains_usize(a[0 .. 4], 1) == false); - assert(contains_usize(a[0 .. 4], 4294967295) == false); - assert(contains_usize(a[0 .. 4], 4294967297) == false); - assert(contains_usize(a[0 .. 4], 9223372036854775808) == false); - assert(contains_usize(a[0 .. 0], 7) == false); -} - -/// [i8]::contains(&x): every expected value was printed by rustc 1.99 running `a.contains(&x)` on the same array, for a -/// member (first, middle, last), a non-member and the neighbours of the edge values; the empty slice contains nothing. -test std_contains_of_i8_is_rusts { - const a : [4]i8 = [7, -128, 127, -1]; - assert(contains_i8(a[0 .. 4], 7) == true); - assert(contains_i8(a[0 .. 4], -128) == true); - assert(contains_i8(a[0 .. 4], 127) == true); - assert(contains_i8(a[0 .. 4], -1) == true); - assert(contains_i8(a[0 .. 4], 0) == false); - assert(contains_i8(a[0 .. 4], 1) == false); - assert(contains_i8(a[0 .. 4], -127) == false); - assert(contains_i8(a[0 .. 4], 126) == false); - assert(contains_i8(a[0 .. 0], 7) == false); -} - -/// [i16]::contains(&x): every expected value was printed by rustc 1.99 running `a.contains(&x)` on the same array, for a -/// member (first, middle, last), a non-member and the neighbours of the edge values; the empty slice contains nothing. -test std_contains_of_i16_is_rusts { - const a : [4]i16 = [7, -32768, 32767, -1]; - assert(contains_i16(a[0 .. 4], 7) == true); - assert(contains_i16(a[0 .. 4], -32768) == true); - assert(contains_i16(a[0 .. 4], 32767) == true); - assert(contains_i16(a[0 .. 4], -1) == true); - assert(contains_i16(a[0 .. 4], 0) == false); - assert(contains_i16(a[0 .. 4], 1) == false); - assert(contains_i16(a[0 .. 4], -32767) == false); - assert(contains_i16(a[0 .. 4], 32766) == false); - assert(contains_i16(a[0 .. 0], 7) == false); -} - -/// [i32]::contains(&x): every expected value was printed by rustc 1.99 running `a.contains(&x)` on the same array, for a -/// member (first, middle, last), a non-member and the neighbours of the edge values; the empty slice contains nothing. -test std_contains_of_i32_is_rusts { - const a : [4]i32 = [7, I32_MIN, 2147483647, -1]; - assert(contains_i32(a[0 .. 4], 7) == true); - assert(contains_i32(a[0 .. 4], I32_MIN) == true); - assert(contains_i32(a[0 .. 4], 2147483647) == true); - assert(contains_i32(a[0 .. 4], -1) == true); - assert(contains_i32(a[0 .. 4], 0) == false); - assert(contains_i32(a[0 .. 4], 1) == false); - assert(contains_i32(a[0 .. 4], -2147483647) == false); - assert(contains_i32(a[0 .. 4], 2147483646) == false); - assert(contains_i32(a[0 .. 0], 7) == false); -} - -/// [i64]::contains(&x): every expected value was printed by rustc 1.99 running `a.contains(&x)` on the same array, for a -/// member (first, middle, last), a non-member and the neighbours of the edge values; the empty slice contains nothing. -test std_contains_of_i64_is_rusts { - const a : [4]i64 = [7, I64_MIN, 9223372036854775807, -1]; - assert(contains_i64(a[0 .. 4], 7) == true); - assert(contains_i64(a[0 .. 4], I64_MIN) == true); - assert(contains_i64(a[0 .. 4], 9223372036854775807) == true); - assert(contains_i64(a[0 .. 4], -1) == true); - assert(contains_i64(a[0 .. 4], 0) == false); - assert(contains_i64(a[0 .. 4], 1) == false); - assert(contains_i64(a[0 .. 4], -9223372036854775807) == false); - assert(contains_i64(a[0 .. 4], 9223372036854775806) == false); - assert(contains_i64(a[0 .. 0], 7) == false); -} - -/// [f32]::contains(&x): every expected value was printed by rustc 1.99 running `a.contains(&x)` on the same array, for a -/// member (first, middle, last), a non-member and the neighbours of the edge values; the empty slice contains nothing. -test std_contains_of_f32_is_rusts { - const a : [4]f32 = [1.5, 0.0, -2.25, 100.0]; - assert(contains_f32(a[0 .. 4], 1.5) == true); - assert(contains_f32(a[0 .. 4], 0.0) == true); - assert(contains_f32(a[0 .. 4], -0.0) == true); - assert(contains_f32(a[0 .. 4], -2.25) == true); - assert(contains_f32(a[0 .. 4], 100.0) == true); - assert(contains_f32(a[0 .. 4], 1.25) == false); - assert(contains_f32(a[0 .. 4], 3.5) == false); - assert(contains_f32(a[0 .. 0], 1.5) == false); - const nan : f32 = from_bits_f32(0x7FC00000); - const b : [2]f32 = [1.5, nan]; - assert(contains_f32(b[0 .. 2], nan) == false); - assert(contains_f32(a[0 .. 4], nan) == false); -} - -/// [f64]::contains(&x): every expected value was printed by rustc 1.99 running `a.contains(&x)` on the same array, for a -/// member (first, middle, last), a non-member and the neighbours of the edge values; the empty slice contains nothing. -test std_contains_of_f64_is_rusts { - const a : [4]f64 = [1.5, 0.0, -2.25, 100.0]; - assert(contains_f64(a[0 .. 4], 1.5) == true); - assert(contains_f64(a[0 .. 4], 0.0) == true); - assert(contains_f64(a[0 .. 4], -0.0) == true); - assert(contains_f64(a[0 .. 4], -2.25) == true); - assert(contains_f64(a[0 .. 4], 100.0) == true); - assert(contains_f64(a[0 .. 4], 1.25) == false); - assert(contains_f64(a[0 .. 4], 3.5) == false); - assert(contains_f64(a[0 .. 0], 1.5) == false); - const nan : f64 = from_bits_f64(0x7FF8000000000000); - const b : [2]f64 = [1.5, nan]; - assert(contains_f64(b[0 .. 2], nan) == false); - assert(contains_f64(a[0 .. 4], nan) == false); -} - /// str::contains(char) of a char in a variable: every expected value was printed by rustc 1.99 running `t.contains(c)`; the /// texts hold one-, two-, three- and four-byte chars and enter as byte arrays (t27 source is ASCII), the chars as scalar values. test std_contains_of_a_char_is_rusts {