vyre 0.4.0

GPU compute intermediate representation with a standard operation library
Documentation
//! URL percent decode operation as an IR composition.

/// CPU-independent IR kernel for URL percent-encoded byte escapes.
pub mod kernel {
    use super::super::shared::{and, hex_nibble, BYTE_BOUNDED_LAWS};
    use crate::ir::{BufferDecl, DataType, Expr, Node, Program};
    use crate::ops::{OpSpec, BYTES_TO_BYTES_INPUTS, BYTES_TO_BYTES_OUTPUTS};

    /// GPU region decoder for URL percent-encoded byte escapes.
    #[derive(Debug, Clone, Copy, Default)]
    pub struct UrlDecode;

    impl UrlDecode {
        /// Declarative operation specification.
        pub const SPEC: OpSpec = OpSpec::composition(
            "decode.url",
            BYTES_TO_BYTES_INPUTS,
            BYTES_TO_BYTES_OUTPUTS,
            BYTE_BOUNDED_LAWS,
            Self::program,
        );

        /// Build the canonical IR program.
        #[must_use]
        pub fn program() -> Program {
            let idx = Expr::var("idx");
            let byte = Expr::load("input", idx.clone());
            let percent = Expr::eq(byte.clone(), Expr::u32(u32::from(b'%')));
            let plus = Expr::eq(byte.clone(), Expr::u32(u32::from(b'+')));
            Program::new(
                vec![
                    BufferDecl::read("input", 0, DataType::Bytes),
                    BufferDecl::output("out", 1, DataType::Bytes),
                ],
                [64, 1, 1],
                vec![
                    Node::let_bind("idx", Expr::gid_x()),
                    Node::if_then(
                        and(
                            Expr::lt(idx.clone(), Expr::buf_len("input")),
                            Expr::lt(idx.clone(), Expr::buf_len("out")),
                        ),
                        vec![Node::store(
                            "out",
                            idx.clone(),
                            Expr::select(
                                and(
                                    percent,
                                    Expr::lt(
                                        Expr::add(idx.clone(), Expr::u32(2)),
                                        Expr::buf_len("input"),
                                    ),
                                ),
                                decoded_escape(idx.clone()),
                                Expr::select(plus, Expr::u32(u32::from(b' ')), byte),
                            ),
                        )],
                    ),
                ],
            )
        }
    }

    /// Decode the `%NN` escape beginning at `idx`.
    #[must_use]
    pub fn decoded_escape(idx: Expr) -> Expr {
        let hi = hex_nibble(Expr::load("input", Expr::add(idx.clone(), Expr::u32(1))));
        let lo = hex_nibble(Expr::load("input", Expr::add(idx, Expr::u32(2))));
        Expr::bitor(Expr::shl(hi, Expr::u32(4)), lo)
    }
}

pub use kernel::UrlDecode;