Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

nushell/modules/proquint.nu

Raw
const CONSONANTS = "bdfghjklmnprstvz" | split chars
const VOWELS = "aiou" | split chars

def consonant-value [letter: string] {
    $CONSONANTS | enumerate | where item == $letter | first | get index
}

def vowel-value [letter: string] {
    $VOWELS | enumerate | where item == $letter | first | get index
}

# Encode binary as lowercase proquint blocks.
# Each five-letter CVCVC block holds two bytes; a final three-letter CVC block
# holds one byte. Its last consonant is restricted to b, d, f, or g.
export def main [value?: binary] {
    let bytes = if $value == null { $in } else { $value }
    if ($bytes | describe) != "binary" {
        error make {msg: "proquint requires binary input"}
    }

    $bytes
    | chunks 2
    | each {|chunk|
        let high = $chunk.0
        let low = $chunk.1?
        if $low == null {
            [
                ($CONSONANTS | get ($high // 16))
                ($VOWELS | get (($high // 4) mod 4))
                ($CONSONANTS | get ($high mod 4))
            ] | str join
        } else {
            let word = $high * 256 + $low
            [
                ($CONSONANTS | get ($word // 4096))
                ($VOWELS | get (($word // 1024) mod 4))
                ($CONSONANTS | get (($word // 64) mod 16))
                ($VOWELS | get (($word // 16) mod 4))
                ($CONSONANTS | get ($word mod 16))
            ] | str join
        }
    }
    | str join "-"
}

# Decode proquints to binary, without inferring a Nushell value type.
export def decode [value?: string] {
    let text = if $value == null { $in } else { $value }
    if ($text | describe) != "string" {
        error make {msg: "proquint decode requires text input"}
    }
    if $text == "" { return 0x[] }

    let blocks = $text | split row "-"
    let last = ($blocks | length) - 1
    $blocks
    | enumerate
    | each {|entry|
        let block = $entry.item
        let letters = $block | split chars
        if $block =~ '^[bdfghjklmnprstvz][aiou][bdfghjklmnprstvz][aiou][bdfghjklmnprstvz]$' {
            let word = (
                (consonant-value ($letters | get 0)) * 4096
                + (vowel-value ($letters | get 1)) * 1024
                + (consonant-value ($letters | get 2)) * 64
                + (vowel-value ($letters | get 3)) * 16
                + (consonant-value ($letters | get 4))
            )
            [
                (($word // 256) | into binary --compact --endian big)
                (($word mod 256) | into binary --compact --endian big)
            ] | bytes collect
        } else if $entry.index == $last and $block =~ '^[bdfghjklmnprstvz][aiou][bdfg]$' {
            let byte = (
                (consonant-value ($letters | get 0)) * 16
                + (vowel-value ($letters | get 1)) * 4
                + (consonant-value ($letters | get 2))
            )
            $byte | into binary --compact --endian big
        } else {
            error make {msg: $"invalid proquint block: ($block)"}
        }
    }
    | bytes collect
}