nix-configs/programs/flip-bool/src/main.rs

117 lines
3.2 KiB
Rust
Raw Normal View History

2025-03-20 14:53:11 +01:00
#![feature(iter_array_chunks)]
#![feature(round_char_boundary)]
#![feature(iter_collect_into)]
#![feature(pattern)]
use std::{
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"],
];
2025-03-10 14:22:10 +01:00
fn main() {
let mut input = String::new();
let mut stdin = std::io::stdin();
let mut stdout = std::io::stdout();
stdin.read_to_string(&mut input).unwrap();
2025-03-20 14:53:11 +01:00
let bool_locs = find_bools(&input);
2025-03-10 14:22:10 +01:00
stdout
2025-03-20 14:53:11 +01:00
.write_all(replace_bools(&mut input, bool_locs).as_bytes())
2025-03-10 14:22:10 +01:00
.unwrap();
}
2025-03-20 14:53:11 +01:00
type BoolLocs = [[Vec<usize>; 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::<Vec<_>>();
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<usize>; 2]; BOOL_COUNT] {
let mut res = Vec::with_capacity(BOOL_COUNT);
BOOLS
.iter()
.flatten()
.map(|it| {
input
.match_indices(it)
.filter_map(|it| {
2025-03-21 14:15:12 +01:00
fn char_guard(c: char) -> bool {
!(c.is_alphanumeric() || c.is_contained_in("-_"))
}
let last_idx = it.0 + it.1.len();
2025-03-20 14:53:11 +01:00
2025-03-21 14:15:12 +01:00
(it.0 > 0
&& last_idx < input.len()
&& char_guard(
2025-03-20 14:53:11 +01:00
input[it.1.floor_char_boundary(it.0 - 1)..it.0]
.chars()
.last()
.unwrap(),
2025-03-21 14:15:12 +01:00
)
&& char_guard(
2025-03-20 14:53:11 +01:00
input[(last_idx)..(input.ceil_char_boundary(last_idx + 1))]
.chars()
.last()
.unwrap(),
2025-03-21 14:15:12 +01:00
))
.then_some(it.0)
2025-03-20 14:53:11 +01:00
})
.collect()
})
.array_chunks::<2>()
.collect_into(&mut res);
res.try_into().unwrap()
}