Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Senryoku committed Oct 31, 2023
1 parent 09c8e07 commit d1c93f5
Show file tree
Hide file tree
Showing 76 changed files with 529,710 additions and 0 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/ts-lib.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: TS Lib

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
ts-lib:
strategy:
matrix:
node-version: [18.x]
os: [ubuntu-latest, windows-latest, macos-latest]

runs-on: ${{ matrix.os }}

defaults:
run:
working-directory: ./ts-lib

steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
cache-dependency-path: ts-lib/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run tests
run: npm test
- name: Safari Tests
if: matrix.os == 'macos-latest'
run: npm run test:safari
- name: Chrome Tests
if: always()
run: npm run test:chrome
- name: Firefox Tests
if: always()
run: npm run test:firefox
- name: Edge Tests
if: always()
run: npm run test:edge
- name: Benchmarks
if: always()
run: npm run bench
24 changes: 24 additions & 0 deletions .github/workflows/zig.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Zig Build and Test

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- uses: goto-bus-stop/setup-zig@v2
- run: zig build test --summary all
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: goto-bus-stop/setup-zig@v2
- run: zig fmt --check src/*.zig
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
zig-cache
zig-out

build.bat
57 changes: 57 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# smol-string

`smol-string` is a compression library designed to be used with browsers' `localStorage` (and `sessionStorage`). It is intended to be a faster alternative to [`lz-string`](https://github.com/pieroxy/lz-string).

It is composed of the core algorithm written in [Zig](https://ziglang.org/) compiled to Wasm and a wrapper in the form of a Typescript library.

I originally made sure it produced valid UTF-16 strings to ensure browser compatibility, however this doesn't seem to be necessary for any of the tested browsers. The default can now produce technically invalid UTF-16 strings. I might add back a way to limit it to valid UTF-16 if there's a need.

## Usage

```ts
import { compress, decompress } from "smol-string";

const input = "Any JS String";

const compressed = compress(input);
const decompressed = decompress(compressed);
```

The default `compress`/`decompress` are optimized for speed and produce bigger output.
`smol-string` also provide a bit packed version which yield compressed sizes similar to `lz-string`, while still being faster:

```ts
import { compressPacked, decompressPacked } from "smol-string-packed";

const compressed = compressPacked(input);
const decompressed = decompressPacked(compressed);
```

Each version is distributed as a separate package to reduce bundle size. You don't want to mix them anyway.

Finally, there's an async version offloading the processing to a webworker. API is identical, expect that each function returns a promise:

```ts
import { compress, decompress } from "smol-string-worker";
// Or
import { compressPacked, decompressPacked } from "smol-string-worker-packed";

const compressed = await compress(input);
const decompressed = await decompress(compressed);
```

## Todos

- Integrate the run length at the start of the output stream instead of using a end sentinel?

## Build

```sh
zig build # Builds the wasm modules and copies them to `ts-lib/src`.
```

```sh
cd ts-lib
npm ci # Installs Dependencies.
npm run build # Builds the Typescript library to `ts-lib/dist`.
```
79 changes: 79 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const std = @import("std");

fn copyLib(self: *std.build.Step, progress: *std.Progress.Node) !void {
_ = progress;
_ = self;

std.fs.cwd().copyFile("zig-out/lib/smol-string.wasm", std.fs.cwd(), "ts-lib/src/module.wasm", .{}) catch |err| {
std.log.err("Unable to copy smol-string.wasm to www/: {s}", .{@errorName(err)});
};
std.fs.cwd().copyFile("zig-out/lib/smol-string-packed.wasm", std.fs.cwd(), "ts-lib/src/module-packed.wasm", .{}) catch |err| {
std.log.err("Unable to copy smol-string-packed.wasm to www/: {s}", .{@errorName(err)});
};
}

// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});

// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .ReleaseSmall });

var lib = b.addSharedLibrary(.{
.name = "smol-string",
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
.root_source_file = .{ .path = "src/wasm.zig" },
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
.optimize = .ReleaseSmall,
});
lib.rdynamic = true;

var lib_packed = b.addSharedLibrary(.{
.name = "smol-string-packed",
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
.root_source_file = .{ .path = "src/wasmPacked.zig" },
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
.optimize = .ReleaseSmall,
});
lib_packed.rdynamic = true;

// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
// step when running `zig build`).
b.installArtifact(lib);
b.installArtifact(lib_packed);

const copyStep = b.step("copy", "copy libraries to www/");
copyStep.dependOn(&lib.step);
copyStep.dependOn(&lib_packed.step);
copyStep.dependOn(b.getInstallStep());
copyStep.makeFn = copyLib;

b.default_step = copyStep;

// Creates a step for unit testing. This only builds the test executable
// but does not run it.
const unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/testAll.zig" },
.target = target,
.optimize = optimize,
});

const run_unit_tests = b.addRunArtifact(unit_tests);

// Similar to creating the run step earlier, this exposes a `test` step to
// the `zig build --help` menu, providing a way for the user to request
// running the unit tests.
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
}
1 change: 1 addition & 0 deletions docs/assets/1MB-c4d2b939.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/assets/512KB-af4b69ed.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/assets/BenchmarksView-f725007c.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/assets/DocumentationView-2c93ffff.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions docs/assets/LibBenchmark-c0c71255.js

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions docs/assets/index-a84867ae.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/assets/index-acfa1921.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/assets/rw_large-2123ae92.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/assets/rw_medium-9bc89782.js

Large diffs are not rendered by default.

Binary file added docs/favicon.ico
Binary file not shown.
15 changes: 15 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/smol-string/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>smol-string</title>
<script type="module" crossorigin src="/smol-string/assets/index-a84867ae.js"></script>
<link rel="stylesheet" href="/smol-string/assets/index-acfa1921.css">
</head>
<body>
<div id="app"></div>

</body>
</html>
Loading

0 comments on commit d1c93f5

Please sign in to comment.