diff --git a/flake.nix b/flake.nix index 7cb1cfb..8f30908 100644 --- a/flake.nix +++ b/flake.nix @@ -50,7 +50,6 @@ pkgs = nixpkgs.legacyPackages.${system}; pkgs-stable = nixpkgs-stable.legacyPackages.${system}; pkgs-unstable-small = nixpkgs-unstable-small.legacyPackages.${system}; - crane-lib = crane.mkLib nixpkgs.legacyPackages.${system}; rs-toolchain = with fenix.packages.${system}; combine [ complete.toolchain @@ -59,6 +58,7 @@ # cargo = rs-toolchain; # rustc = rs-toolchain; # }; + crane-lib = (crane.mkLib nixpkgs.legacyPackages.${system}).overrideToolchain rs-toolchain; rs-programs = final: prev: { # s10e-jrnl = rs-platform.buildRustPackage { # pname = "jrnl"; diff --git a/programs/flip-bool/src/main.rs b/programs/flip-bool/src/main.rs index 3ae9375..299685f 100644 --- a/programs/flip-bool/src/main.rs +++ b/programs/flip-bool/src/main.rs @@ -1,4 +1,22 @@ -use std::io::{Read, Write}; +#![feature(iter_array_chunks)] +#![feature(round_char_boundary)] +#![feature(iter_collect_into)] +#![feature(pattern)] + +use std::{ + hint::black_box, + io::{Read, Write}, + str::pattern::Pattern, +}; + +const BOOL_COUNT: usize = BOOLS.len(); +const BOOLS: &[[&str; 2]] = &[ + ["false", "true"], + ["False", "True"], + ["FALSE", "TRUE"], + ["0", "1"], + ["no", "yes"], +]; fn main() { let mut input = String::new(); @@ -7,19 +25,95 @@ fn main() { stdin.read_to_string(&mut input).unwrap(); + let bool_locs = find_bools(&input); stdout - .write_all(match input.as_bytes() { - b"true" => b"false", - b"True" => b"False", - b"TRUE" => b"FALSE", - b"false" => b"true", - b"False" => b"True", - b"FALSE" => b"TRUE", - b"1" => b"0", - b"yes" => b"no", - b"0" => b"1", - b"no" => b"yes", - other => other, - }) + .write_all(replace_bools(&mut input, bool_locs).as_bytes()) .unwrap(); } + +type BoolLocs = [[Vec; 2]; BOOL_COUNT]; + +// you thought [`find_bools`] was stupid? this is *so* much worse!!! +fn replace_bools(input: &str, mut bool_locs: BoolLocs) -> String { + let mut result = String::with_capacity(input.len()); + let mut intermediate = input; + let mut flattened = bool_locs + .iter_mut() + .flatten() + .map(|vec| { + vec.reverse(); + vec + }) + .enumerate() + .collect::>(); + + let mut smallest = || { + let min_idx = flattened + .iter() + .min_by(|va, vb| { + va.1.last() + .unwrap_or(&usize::MAX) + .cmp(vb.1.last().unwrap_or(&usize::MAX)) + })? + .0; + + Some((min_idx, flattened[min_idx].1.pop()?)) + }; + + let mut input_idx = 0; + while let Some(item) = smallest() { + let (a, b) = intermediate.split_at(item.1 - input_idx); + input_idx += a.len(); + result += a; + let bool_ = &BOOLS[item.0 / 2]; + input_idx += bool_[item.0 % 2].len(); + result += bool_[if item.0 % 2 == 0 { 1 } else { 0 }]; + let (_, b) = b.split_at(bool_[item.0 % 2].len()); + intermediate = b; + } + + result + intermediate +} + +// this is so fucking stupid +// it also would've been way easier using a regex crate lmao +fn find_bools(input: &str) -> [[Vec; 2]; BOOL_COUNT] { + let mut res = Vec::with_capacity(BOOL_COUNT); + BOOLS + .iter() + .flatten() + .map(|it| { + input + .match_indices(it) + .filter_map(|it| { + let char_guard = |c: char| !(c.is_alphanumeric() || c.is_contained_in("-_")); + let mut allow = true; + + if it.0 > 0 { + allow &= char_guard( + input[it.1.floor_char_boundary(it.0 - 1)..it.0] + .chars() + .last() + .unwrap(), + ); + } + + let last_idx = it.0 + it.1.len(); + if last_idx < input.len() { + allow &= char_guard( + input[(last_idx)..(input.ceil_char_boundary(last_idx + 1))] + .chars() + .last() + .unwrap(), + ); + } + + allow.then_some(it.0) + }) + .collect() + }) + .array_chunks::<2>() + .collect_into(&mut res); + + res.try_into().unwrap() +}