This commit is contained in:
Tove 2025-05-19 15:36:49 +02:00
parent ee280d63ac
commit e183fb64e2
6 changed files with 374 additions and 0 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use nix

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
.direnv/

7
Cargo.lock generated Normal file
View file

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "polyparse"
version = "0.1.0"

6
Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "polyparse"
version = "0.1.0"
edition = "2021"
[dependencies]

9
shell.nix Normal file
View file

@ -0,0 +1,9 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = with pkgs; [
cargo
helix
rust-analyzer
cargo-watch
];
}

349
src/lib.rs Normal file
View file

@ -0,0 +1,349 @@
#[derive(Debug)]
pub enum NapAmount {
N(u8),
X,
AMAYL,
}
#[derive(Debug)]
pub enum ScheduleKind {
Siesta,
Everyman(NapAmount),
DualCore(NapAmount),
Thinkphasic(NapAmount),
TriCore(NapAmount),
QuadCore(NapAmount),
CAMAYL,
Uberman(NapAmount),
Uberman30(NapAmount),
Bimaxion,
Trimaxion,
Zoidberg(NapAmount),
}
impl ScheduleKind {
pub fn from_ident(s: &str) -> Option<ScheduleKind> {
use NapAmount::*;
use ScheduleKind::*;
let s_orig = s.to_uppercase();
let (s, rest) = s_orig
.split_once(|c: char| c.is_numeric() || c == '-')
.unwrap_or((&s_orig, ""));
if s.starts_with("M") {
return Some(Everyman(Self::detect_naps(&s_orig).unwrap_or(N(0))));
}
if s.starts_with("BI") {
if s.contains("MA") {
return Some(Bimaxion);
}
if s.contains("X") || rest.starts_with("X") {
return Some(Everyman(X));
}
return Some(Everyman(N(1)));
}
if s.starts_with("SEG") {
let naps = if s.contains("Y") || rest.starts_with("Y") {
X
} else {
N(0)
};
return Some(DualCore(naps));
}
if s.starts_with("SIE") {
return Some(Siesta);
}
if s.starts_with("E") {
return Some(Everyman(Self::detect_naps(&s_orig).unwrap_or(N(3))));
}
if s.starts_with("DC") || s.starts_with("DUAL") {
return Some(DualCore(Self::detect_naps(&s_orig).unwrap_or(N(0))));
}
if s.starts_with("TH") || s.starts_with("TP") {
return Some(Thinkphasic(Self::detect_naps(&s_orig).unwrap_or(N(1))));
}
if s.starts_with("TC") || s.starts_with("TRI") {
if s.contains("CA") || s.contains("MAY") {
return Some(TriCore(AMAYL));
}
if s.contains("MA") {
return Some(Trimaxion);
}
return Some(TriCore(Self::detect_naps(&s_orig).unwrap_or(N(0))));
}
if s.starts_with("QC") || s.starts_with("QUAD") {
return Some(QuadCore(Self::detect_naps(&s_orig).unwrap_or(N(0))));
}
if s.starts_with("U") || s.starts_with("TES") {
return Some(Uberman(
Self::detect_naps(&s_orig).unwrap_or(N(if s.starts_with("TES") { 4 } else { 6 })),
));
}
if s.starts_with("DY") {
return Some(Uberman30(
Self::detect_naps(&s_orig)
.map(|x| match x {
X => N(4),
x => x,
})
.unwrap_or(N(4)),
));
}
if s.starts_with("ZO") || s.starts_with("ZB") {
return Some(Zoidberg(Self::detect_naps(&s_orig).unwrap_or(N(6))));
}
Self::find_amayl(s)
}
#[rustfmt::skip]
pub fn short_id(&self) -> String {
use NapAmount::*;
use ScheduleKind::*;
match self {
Everyman(N(0)) => format!("Mono"),
Siesta => format!("Siesta"),
Everyman(X) => format!("BiX"),
Everyman(N(n)) => format!("E{n}"),
Everyman(AMAYL) => format!("SEVA"),
DualCore(X) => format!("SegY"),
DualCore(N(n)) => format!("DC{n}"),
DualCore(AMAYL) => format!("DUCA"),
Thinkphasic(X) => format!("TPX"),
Thinkphasic(N(n)) => format!("TP{n}"),
Thinkphasic(AMAYL) => format!("THAMAYL"),
TriCore(X) => format!("TCX"),
TriCore(N(n)) => format!("TC{n}"),
TriCore(AMAYL) => format!("TRICA"),
QuadCore(X) => format!("QCX"),
QuadCore(N(n)) => format!("QC{n}"),
QuadCore(AMAYL) => format!("QCA"),
CAMAYL => format!("CAMA"),
Uberman(X) => format!("UX"),
Uberman(N(4)) => format!("Tesla"),
Uberman(N(n)) => format!("U{n}"),
Uberman(AMAYL) => format!("SPAM"),
Uberman30(X) => format!("invalid"),
Uberman30(N(4)) => format!("Dymax"),
Uberman30(N(n)) => format!("Dymax{n}"),
Uberman30(AMAYL) => format!("SDMA"),
Bimaxion => format!("Bimax"),
Trimaxion => format!("Trimax"),
Zoidberg(X) => format!("ZBX"),
Zoidberg(N(6)) => format!("ZB"),
Zoidberg(N(n)) => format!("ZB{n}"),
Zoidberg(AMAYL) => format!("ZOIDA"),
}
}
#[rustfmt::skip]
pub fn long_id(&self) -> String {
use NapAmount::*;
use ScheduleKind::*;
match self {
Everyman(N(0)) => format!("Monophasic"),
Siesta => format!("Siesta"),
Everyman(X) => format!("Biphasic-X"),
Everyman(N(n)) => format!("Everyman-{n}"),
Everyman(AMAYL) => format!("SEVAMAYL"),
DualCore(X) => format!("Segmented-Y"),
DualCore(N(n)) => format!("DualCore-{n}"),
DualCore(AMAYL) => format!("DUCAMAYL"),
Thinkphasic(X) => format!("Thinkphasic-X"),
Thinkphasic(N(n)) => format!("Thinkphasic-{n}"),
Thinkphasic(AMAYL) => format!("THINKAMAYL"),
TriCore(X) => format!("TriCore-X"),
TriCore(N(n)) => format!("TriCore-{n}"),
TriCore(AMAYL) => format!("TRICAMAYL"),
QuadCore(X) => format!("QuadCore-X"),
QuadCore(N(n)) => format!("QuadCore-{n}"),
QuadCore(AMAYL) => format!("QCAMAYL"),
CAMAYL => format!("CAMAYL"),
Uberman(X) => format!("Uberman-X"),
Uberman(N(4)) => format!("Tesla"),
Uberman(N(n)) => format!("Uberman-{n}"),
Uberman(AMAYL) => format!("SPAMAYL"),
Uberman30(X) => format!("invalid"),
Uberman30(N(4)) => format!("Dymaxion"),
Uberman30(N(n)) => format!("Dymaxion-{n}"),
Uberman30(AMAYL) => format!("SDYMAMAYL"),
Bimaxion => format!("Bimaxion"),
Trimaxion => format!("Trimaxion"),
Zoidberg(X) => format!("Zoidberg-X"),
Zoidberg(N(6)) => format!("Zoidberg"),
Zoidberg(N(n)) => format!("Zoidberg-{n}"),
Zoidberg(AMAYL) => format!("ZOIDAMAYL"),
}
}
fn find_amayl(mut s: &str) -> Option<ScheduleKind> {
use NapAmount::*;
use ScheduleKind::*;
if s.starts_with("S") {
s = &s[1..];
}
if s.starts_with("EV") {
return Some(Everyman(AMAYL));
}
if s.starts_with("PA") {
return Some(Uberman(AMAYL));
}
if s.starts_with("DMA") || s.starts_with("DYMA") {
return Some(Uberman30(AMAYL));
}
if s.starts_with("DUCA") {
return Some(DualCore(AMAYL));
}
if s.starts_with("CAM") {
return Some(CAMAYL);
}
if s.starts_with("TCA") || s.starts_with("TRICA") {
return Some(TriCore(AMAYL));
}
if s.contains("Q") && s.contains("A") {
return Some(QuadCore(AMAYL));
}
if s.starts_with("ZOIDA") {
return Some(Zoidberg(AMAYL));
}
if s.starts_with("THA") || s.starts_with("TPA") || s.starts_with("THINKA") {
return Some(Thinkphasic(AMAYL));
}
None
}
fn detect_naps(full_name: &str) -> Option<NapAmount> {
full_name
.find(|x: char| x.is_numeric() || x == 'X')
.map(|begin| {
let xcheck = &full_name[begin - 1..=begin];
if xcheck == "EX" || xcheck == "LX" {
return None;
}
full_name[begin..]
.find(|x: char| !x.is_numeric() && x != 'X')
.or(Some(full_name.len() - begin))
.map(|end| (begin, end + begin))
})
.flatten()
.map(|(begin, end)| {
let s = &full_name[begin..end];
if s == "X" {
return Some(NapAmount::X);
}
Some(NapAmount::N(s.parse::<u8>().ok()?))
})
.flatten()
}
}
#[derive(Debug)]
pub struct Schedule {
kind: ScheduleKind,
extended: bool,
flexible: bool,
stiff: bool,
modified: bool,
shortened: bool,
recovery: bool,
}
impl Schedule {
pub fn from_ident(s: &str) -> Option<Self> {
let s = s.to_uppercase();
let kind = ScheduleKind::from_ident(&s)?;
let Some(begin) = try_find_with_number(&s)
.or(try_find_with_dash(&s))
.or(try_find_by_string(&s))
else {
return Some(Self {
kind,
extended: false,
flexible: false,
stiff: false,
modified: false,
shortened: false,
recovery: false,
});
};
let s = &s[begin..];
let flexible = s.contains("FLEX") || s.contains("FLX");
let s = s.replace("FLEX", "----");
let extended = s.contains("EX") || s == "E";
let stiff = s.contains("STIFF");
let shortened = s.contains("SHO");
let modified = s.contains("MOD") || s.contains("MD");
let recovery = s.contains("REC");
Some(Self {
kind,
extended,
flexible,
stiff,
modified,
shortened,
recovery,
})
}
pub fn short_id(&self) -> String {
let mut id = self.kind.short_id();
if self.shortened {
id += "sho";
}
if self.stiff {
id += "stiff"
}
if self.extended {
if !self.flexible && !self.stiff && !self.shortened && !self.modified && !self.recovery
{
id += "e";
} else {
id += "ex";
}
}
if self.flexible {
id += "flex";
}
if self.modified {
id += "mod";
}
if self.recovery {
id += "rec";
}
id
}
pub fn long_id(&self) -> String {
let mut id = self.kind.long_id();
if self.shortened {
id += "-Shortened";
}
if self.stiff {
id += "-Stiff"
}
if self.extended {
id += "-Extended"
}
if self.flexible {
id += "-Flexible";
}
if self.modified {
id += "-Modified";
}
if self.recovery {
id += "-Recovery";
}
id
}
}
fn try_find_with_number(s: &str) -> Option<usize> {
s.rfind(char::is_numeric).map(|x| x + 1)
}
fn try_find_with_dash(s: &str) -> Option<usize> {
s.find('-').map(|x| x + 1)
}
fn try_find_by_string(s: &str) -> Option<usize> {
s.find("EX")
.or(s.find("MOD"))
.or(s.find("MD"))
.or(s.find("FLEX"))
.or(s.find("FLX"))
.or(s.find("STIFF"))
.or(s.find("SHO"))
.or(s.find("REC"))
}