# lzbase62

LZSS string compression with base-62 safe text output.

This crate compresses a string with an LZSS sliding-window dictionary, then
frames the result in a 62-character alphabet (`A-Za-z0-9`) so the output is plain
text. The format is unique to this crate and round-trips with itself.

## Install

```toml
[dependencies]
lzbase62 = "0.1"
```

## Use

```rust
let packed = lzbase62::compress("hello hello hello");
assert_eq!(packed, "tYVccfxGM");
assert_eq!(lzbase62::decompress(&packed), "hello hello hello");
```

Empty input returns an empty string. Characters outside the alphabet are skipped
during decompression, and malformed input never panics.

## Streaming

`compress_with` and `decompress_with` take an `Options` value with optional
`on_data` and `on_end` callbacks. With `on_data` set, output is delivered through
the callback in chunks. `compress_with` then returns an empty string, while
`decompress_with` still returns the full result.

```rust
let mut chunks = String::new();
let returned = lzbase62::compress_with(
    "hello hello hello",
    lzbase62::Options::new().on_data(|c| chunks.push_str(c)),
);
assert_eq!(returned, "");
assert_eq!(lzbase62::decompress(&chunks), "hello hello hello");
```

## Encoding notes

The algorithm works over UTF-16 code units, matching JavaScript string
semantics. Surrogate pairs such as emoji are processed as two units and
round-trip cleanly. The alphabet order is uppercase, then lowercase, then
digits. It serves as a symbol table, not a positional base, so the output is not
interoperable with standard base62 or other compressors.

`decompress` returns a `String`, so a decoded lone surrogate becomes `U+FFFD`.
A `decompress(compress(s))` round-trip stays exact, since compressing a `&str`
cannot produce a lone surrogate. To decode a crafted stream that lands in the
surrogate range, call `decompress_units`, which returns raw `Vec<u16>` code
units.

## License

Licensed under the [MIT license](LICENSE).
