Skip to content

Commit 4156803

Browse files
committed
feat: finalize streaming api foundation
1 parent 175d6a9 commit 4156803

53 files changed

Lines changed: 1618 additions & 168 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@ jobs:
8282
cd algorithms/huffman/go
8383
go vet ./...
8484
go test ./...
85-
go build -o huffman_go .
85+
go build -o huffman_go ./cmd
8686
8787
- name: Build Arithmetic Go
8888
run: |
8989
cd algorithms/arithmetic/go
9090
go vet ./...
9191
go test ./...
92-
go build -o arithmetic_go .
92+
go build -o arithmetic_go ./cmd
9393
9494
- name: Build Range coder Go
9595
run: |
@@ -103,7 +103,7 @@ jobs:
103103
cd algorithms/rle/go
104104
go vet ./...
105105
go test ./...
106-
go build -o rle_go .
106+
go build -o rle_go ./cmd
107107
108108
# Build and check Rust implementations
109109
build-rust:
@@ -121,42 +121,39 @@ jobs:
121121

122122
- name: Check Rust formatting
123123
run: |
124-
for file in algorithms/huffman/rust/main.rs algorithms/arithmetic/rust/main.rs algorithms/rle/rust/main.rs; do
125-
if [ -f "$file" ]; then
126-
rustfmt --check "$file" || exit 1
127-
fi
128-
done
129-
if [ -f "algorithms/range/rust/Cargo.toml" ]; then
130-
cd algorithms/range/rust && cargo fmt --check
131-
fi
124+
cargo fmt --manifest-path algorithms/huffman/rust/Cargo.toml --check
125+
cargo fmt --manifest-path algorithms/arithmetic/rust/Cargo.toml --check
126+
cargo fmt --manifest-path algorithms/range/rust/Cargo.toml --check
127+
cargo fmt --manifest-path algorithms/rle/rust/Cargo.toml --check
128+
cargo fmt --manifest-path algorithms/shared/rust/Cargo.toml --check
132129
133130
- name: Build Huffman Rust
134131
run: |
135132
cd algorithms/huffman/rust
136-
rustc -O main.rs -o huffman_rust
137-
rustc --test main.rs -o huffman_rust_test
138-
./huffman_rust_test
133+
cargo clippy --all-targets -- -D warnings
134+
cargo test
135+
cargo build --bin huffman_rust --release
139136
140137
- name: Build Arithmetic Rust
141138
run: |
142139
cd algorithms/arithmetic/rust
143-
rustc -O main.rs -o arithmetic_rust
144-
rustc --test main.rs -o arithmetic_rust_test
145-
./arithmetic_rust_test
140+
cargo clippy --all-targets -- -D warnings
141+
cargo test
142+
cargo build --bin arithmetic_rust --release
146143
147144
- name: Build and check Range coder Rust
148145
run: |
149146
cd algorithms/range/rust
150-
cargo clippy -- -D warnings
147+
cargo clippy --all-targets -- -D warnings
151148
cargo test
152149
cargo build --release
153150
154151
- name: Build RLE Rust
155152
run: |
156153
cd algorithms/rle/rust
157-
rustc -O main.rs -o rle_rust
158-
rustc --test main.rs -o rle_rust_test
159-
./rle_rust_test
154+
cargo clippy --all-targets -- -D warnings
155+
cargo test
156+
cargo build --bin rle_rust --release
160157
161158
# Verify encode/decode correctness across languages
162159
test-correctness:
@@ -200,10 +197,10 @@ jobs:
200197
(cd algorithms/rle/go && go build -o rle_go ./cmd)
201198
202199
# Rust
203-
(cd algorithms/huffman/rust && rustc -O main.rs -o huffman_rust)
204-
(cd algorithms/arithmetic/rust && rustc -O main.rs -o arithmetic_rust)
200+
(cd algorithms/huffman/rust && cargo build --bin huffman_rust --release)
201+
(cd algorithms/arithmetic/rust && cargo build --bin arithmetic_rust --release)
205202
(cd algorithms/range/rust && cargo build --bin rangecoder --release)
206-
(cd algorithms/rle/rust && rustc -O main.rs -o rle_rust)
203+
(cd algorithms/rle/rust && cargo build --bin rle_rust --release)
207204
208205
- name: Test Huffman correctness
209206
run: |
@@ -220,16 +217,16 @@ jobs:
220217
diff "$TEST_FILE" /tmp/huf_go.dec
221218
222219
echo "Testing Huffman Rust..."
223-
./algorithms/huffman/rust/huffman_rust encode "$TEST_FILE" /tmp/huf_rust.enc
224-
./algorithms/huffman/rust/huffman_rust decode /tmp/huf_rust.enc /tmp/huf_rust.dec
220+
./algorithms/huffman/rust/target/release/huffman_rust encode "$TEST_FILE" /tmp/huf_rust.enc
221+
./algorithms/huffman/rust/target/release/huffman_rust decode /tmp/huf_rust.enc /tmp/huf_rust.dec
225222
diff "$TEST_FILE" /tmp/huf_rust.dec
226223
227224
echo "Testing cross-language (C++ encode -> Go decode)..."
228225
./algorithms/huffman/go/huffman_go decode /tmp/huf_cpp.enc /tmp/huf_cross_go.dec
229226
diff "$TEST_FILE" /tmp/huf_cross_go.dec
230227
231228
echo "Testing cross-language (C++ encode -> Rust decode)..."
232-
./algorithms/huffman/rust/huffman_rust decode /tmp/huf_cpp.enc /tmp/huf_cross_rust.dec
229+
./algorithms/huffman/rust/target/release/huffman_rust decode /tmp/huf_cpp.enc /tmp/huf_cross_rust.dec
233230
diff "$TEST_FILE" /tmp/huf_cross_rust.dec
234231
235232
echo "Huffman tests passed!"
@@ -249,16 +246,16 @@ jobs:
249246
diff "$TEST_FILE" /tmp/arith_go.dec
250247
251248
echo "Testing Arithmetic Rust..."
252-
./algorithms/arithmetic/rust/arithmetic_rust encode "$TEST_FILE" /tmp/arith_rust.enc
253-
./algorithms/arithmetic/rust/arithmetic_rust decode /tmp/arith_rust.enc /tmp/arith_rust.dec
249+
./algorithms/arithmetic/rust/target/release/arithmetic_rust encode "$TEST_FILE" /tmp/arith_rust.enc
250+
./algorithms/arithmetic/rust/target/release/arithmetic_rust decode /tmp/arith_rust.enc /tmp/arith_rust.dec
254251
diff "$TEST_FILE" /tmp/arith_rust.dec
255252
256253
echo "Testing cross-language (C++ encode -> Go decode)..."
257254
./algorithms/arithmetic/go/arithmetic_go decode /tmp/arith_cpp.enc /tmp/arith_cross_go.dec
258255
diff "$TEST_FILE" /tmp/arith_cross_go.dec
259256
260257
echo "Testing cross-language (C++ encode -> Rust decode)..."
261-
./algorithms/arithmetic/rust/arithmetic_rust decode /tmp/arith_cpp.enc /tmp/arith_cross_rust.dec
258+
./algorithms/arithmetic/rust/target/release/arithmetic_rust decode /tmp/arith_cpp.enc /tmp/arith_cross_rust.dec
262259
diff "$TEST_FILE" /tmp/arith_cross_rust.dec
263260
264261
echo "Arithmetic tests passed!"
@@ -315,16 +312,16 @@ jobs:
315312
diff "$TEST_FILE" /tmp/rle_go.dec
316313
317314
echo "Testing RLE Rust..."
318-
./algorithms/rle/rust/rle_rust encode "$TEST_FILE" /tmp/rle_rust.enc
319-
./algorithms/rle/rust/rle_rust decode /tmp/rle_rust.enc /tmp/rle_rust.dec
315+
./algorithms/rle/rust/target/release/rle_rust encode "$TEST_FILE" /tmp/rle_rust.enc
316+
./algorithms/rle/rust/target/release/rle_rust decode /tmp/rle_rust.enc /tmp/rle_rust.dec
320317
diff "$TEST_FILE" /tmp/rle_rust.dec
321318
322319
echo "Testing cross-language (C++ encode -> Go decode)..."
323320
./algorithms/rle/go/rle_go decode /tmp/rle_cpp.enc /tmp/rle_cross_go.dec
324321
diff "$TEST_FILE" /tmp/rle_cross_go.dec
325322
326323
echo "Testing cross-language (C++ encode -> Rust decode)..."
327-
./algorithms/rle/rust/rle_rust decode /tmp/rle_cpp.enc /tmp/rle_cross_rust.dec
324+
./algorithms/rle/rust/target/release/rle_rust decode /tmp/rle_cpp.enc /tmp/rle_cross_rust.dec
328325
diff "$TEST_FILE" /tmp/rle_cross_rust.dec
329326
330327
echo "RLE tests passed!"

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ coverage.out
4646
**/huffman_rust_test
4747
**/arithmetic_rust_test
4848
**/rle_rust_test
49+
**/test_lifecycle
50+
51+
# Local environments
52+
.venv/
53+
.omc/
4954

5055
# CMake generated files
5156
CMakeCache.txt

Makefile

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.PHONY: build build-huffman build-arithmetic build-range build-rle \
22
test test-huffman-go test-arithmetic-go test-range-go test-rle-go \
3+
test-shared-cpp test-shared-go test-shared-rust \
34
test-huffman-rust test-arithmetic-rust test-range-rust test-rle-rust \
45
test-data bench clean format lint spec-init spec-list spec-status
56

@@ -8,31 +9,45 @@
89
build: build-huffman build-arithmetic build-range build-rle
910

1011
build-huffman:
11-
g++ -std=c++17 -O2 -Wall -Wextra -Werror algorithms/huffman/cpp/main.cpp -o algorithms/huffman/cpp/huffman_cpp
12+
g++ -std=c++17 -O2 -Wall -Wextra -Werror -Ialgorithms/shared/cpp/include algorithms/shared/cpp/src/buffer_api.cpp algorithms/huffman/cpp/main.cpp -o algorithms/huffman/cpp/huffman_cpp
1213
go build -o algorithms/huffman/go/huffman_go ./algorithms/huffman/go/cmd
13-
rustc -O algorithms/huffman/rust/main.rs -o algorithms/huffman/rust/huffman_rust
14+
cargo build --manifest-path algorithms/huffman/rust/Cargo.toml --bin huffman_rust --release
15+
cp algorithms/huffman/rust/target/release/huffman_rust algorithms/huffman/rust/huffman_rust
1416

1517
build-arithmetic:
16-
g++ -std=c++17 -O2 -Wall -Wextra -Werror algorithms/arithmetic/cpp/main.cpp -o algorithms/arithmetic/cpp/arithmetic_cpp
18+
g++ -std=c++17 -O2 -Wall -Wextra -Werror -Ialgorithms/shared/cpp/include algorithms/shared/cpp/src/buffer_api.cpp algorithms/arithmetic/cpp/main.cpp -o algorithms/arithmetic/cpp/arithmetic_cpp
1719
go build -o algorithms/arithmetic/go/arithmetic_go ./algorithms/arithmetic/go/cmd
18-
rustc -O algorithms/arithmetic/rust/main.rs -o algorithms/arithmetic/rust/arithmetic_rust
20+
cargo build --manifest-path algorithms/arithmetic/rust/Cargo.toml --bin arithmetic_rust --release
21+
cp algorithms/arithmetic/rust/target/release/arithmetic_rust algorithms/arithmetic/rust/arithmetic_rust
1922

2023
build-range:
21-
g++ -std=c++17 -O2 -Wall -Wextra -Werror algorithms/range/cpp/main.cpp -o algorithms/range/cpp/rangecoder_cpp
24+
g++ -std=c++17 -O2 -Wall -Wextra -Werror -Ialgorithms/shared/cpp/include algorithms/shared/cpp/src/buffer_api.cpp algorithms/range/cpp/main.cpp -o algorithms/range/cpp/rangecoder_cpp
2225
go build -o algorithms/range/go/rangecoder_go ./algorithms/range/go/cmd
2326
cargo build --manifest-path algorithms/range/rust/Cargo.toml --release
2427

2528
build-rle:
26-
g++ -std=c++17 -O2 -Wall -Wextra -Werror algorithms/rle/cpp/main.cpp -o algorithms/rle/cpp/rle_cpp
29+
g++ -std=c++17 -O2 -Wall -Wextra -Werror -Ialgorithms/shared/cpp/include algorithms/shared/cpp/src/buffer_api.cpp algorithms/rle/cpp/main.cpp -o algorithms/rle/cpp/rle_cpp
2730
go build -o algorithms/rle/go/rle_go ./algorithms/rle/go/cmd
28-
rustc -O algorithms/rle/rust/main.rs -o algorithms/rle/rust/rle_rust
31+
cargo build --manifest-path algorithms/rle/rust/Cargo.toml --bin rle_rust --release
32+
cp algorithms/rle/rust/target/release/rle_rust algorithms/rle/rust/rle_rust
2933

3034
# ── Test ───────────────────────────────────────────────────────────────────
3135

3236
test: test-data \
37+
test-shared-cpp test-shared-go test-shared-rust \
3338
test-huffman-go test-arithmetic-go test-range-go test-rle-go \
3439
test-huffman-rust test-arithmetic-rust test-range-rust test-rle-rust
3540

41+
test-shared-cpp:
42+
g++ -std=c++17 -O2 -Wall -Wextra -Werror -DCOMPRESSKIT_NO_MAIN -Ialgorithms/shared/cpp/include algorithms/shared/cpp/src/buffer_api.cpp algorithms/huffman/cpp/main.cpp algorithms/arithmetic/cpp/main.cpp algorithms/range/cpp/main.cpp algorithms/rle/cpp/main.cpp algorithms/shared/cpp/tests/test_lifecycle.cpp -o algorithms/shared/cpp/tests/test_lifecycle
43+
./algorithms/shared/cpp/tests/test_lifecycle
44+
45+
test-shared-go:
46+
go test ./algorithms/shared/go/...
47+
48+
test-shared-rust:
49+
cargo test --manifest-path algorithms/shared/rust/Cargo.toml
50+
3651
test-huffman-go:
3752
go test ./algorithms/huffman/go/... ./algorithms/huffman/go/cmd/...
3853

@@ -46,19 +61,16 @@ test-rle-go:
4661
go test ./algorithms/rle/go/... ./algorithms/rle/go/cmd/...
4762

4863
test-huffman-rust:
49-
rustc --test algorithms/huffman/rust/main.rs -o algorithms/huffman/rust/huffman_rust_test
50-
./algorithms/huffman/rust/huffman_rust_test
64+
cargo test --manifest-path algorithms/huffman/rust/Cargo.toml
5165

5266
test-arithmetic-rust:
53-
rustc --test algorithms/arithmetic/rust/main.rs -o algorithms/arithmetic/rust/arithmetic_rust_test
54-
./algorithms/arithmetic/rust/arithmetic_rust_test
67+
cargo test --manifest-path algorithms/arithmetic/rust/Cargo.toml
5568

5669
test-range-rust:
5770
cargo test --manifest-path algorithms/range/rust/Cargo.toml
5871

5972
test-rle-rust:
60-
rustc --test algorithms/rle/rust/main.rs -o algorithms/rle/rust/rle_rust_test
61-
./algorithms/rle/rust/rle_rust_test
73+
cargo test --manifest-path algorithms/rle/rust/Cargo.toml
6274

6375
# ── Data / Bench / Clean ──────────────────────────────────────────────────
6476

@@ -83,19 +95,25 @@ format:
8395
@echo "Formatting Go code..."
8496
gofmt -w algorithms/*/go
8597
@echo "Formatting Rust code..."
86-
rustfmt algorithms/huffman/rust/main.rs algorithms/arithmetic/rust/main.rs algorithms/rle/rust/main.rs 2>/dev/null || true
98+
cargo fmt --manifest-path algorithms/huffman/rust/Cargo.toml 2>/dev/null || true
99+
cargo fmt --manifest-path algorithms/arithmetic/rust/Cargo.toml 2>/dev/null || true
100+
cargo fmt --manifest-path algorithms/rle/rust/Cargo.toml 2>/dev/null || true
87101
cd algorithms/range/rust && cargo fmt 2>/dev/null || true
88102
@echo "Formatting C++ code (if clang-format available)..."
89-
@for f in algorithms/*/cpp/main.cpp; do \
103+
@for f in algorithms/*/cpp/main.cpp algorithms/shared/cpp/src/buffer_api.cpp algorithms/shared/cpp/tests/test_lifecycle.cpp; do \
90104
clang-format -i "$$f" 2>/dev/null || true; \
91105
done
92106
@echo "Done!"
93107

94108
lint:
95109
@echo "Linting Go code..."
96-
go vet ./algorithms/huffman/go/... ./algorithms/arithmetic/go/... ./algorithms/range/go/... ./algorithms/rle/go/... 2>/dev/null || true
110+
go vet ./algorithms/shared/go/... ./algorithms/huffman/go/... ./algorithms/arithmetic/go/... ./algorithms/range/go/... ./algorithms/rle/go/... 2>/dev/null || true
97111
@echo "Linting Rust code..."
112+
cd algorithms/huffman/rust && cargo clippy --all-targets -- -D warnings 2>/dev/null || true
113+
cd algorithms/arithmetic/rust && cargo clippy --all-targets -- -D warnings 2>/dev/null || true
98114
cd algorithms/range/rust && cargo clippy -- -D warnings 2>/dev/null || true
115+
cd algorithms/rle/rust && cargo clippy --all-targets -- -D warnings 2>/dev/null || true
116+
cd algorithms/shared/rust && cargo clippy --all-targets -- -D warnings 2>/dev/null || true
99117
@echo "Done!"
100118

101119
# ── OpenSpec ────────────────────────────────────────────────────────────────

algorithms/arithmetic/cpp/main.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <iostream>
55
#include <string>
66

7+
#include "compresskit/buffer_api.hpp"
8+
79
class BitWriter {
810
public:
911
explicit BitWriter(std::ostream& s) : stream(s), buffer(0), bits_in_buffer(0) {}
@@ -391,6 +393,15 @@ static bool decompress_file(const std::string& input_path, const std::string& ou
391393
return true;
392394
}
393395

396+
bool arithmetic_encode_file(const std::string& input_path, const std::string& output_path) {
397+
return compress_file(input_path, output_path);
398+
}
399+
400+
bool arithmetic_decode_file(const std::string& input_path, const std::string& output_path) {
401+
return decompress_file(input_path, output_path);
402+
}
403+
404+
#ifndef COMPRESSKIT_NO_MAIN
394405
int main(int argc, char** argv) {
395406
if (argc != 4) {
396407
std::cerr << "Usage: " << argv[0] << " encode|decode input output\n";
@@ -403,13 +414,14 @@ int main(int argc, char** argv) {
403414
bool ok = true;
404415

405416
if (mode == "encode") {
406-
ok = compress_file(input_path, output_path);
417+
ok = compresskit::encode_file_via_buffer(arithmetic_encode_file, input_path, output_path);
407418
} else if (mode == "decode") {
408-
ok = decompress_file(input_path, output_path);
419+
ok = compresskit::decode_file_via_buffer(arithmetic_decode_file, input_path, output_path);
409420
} else {
410421
std::cerr << "Unknown mode\n";
411422
return 1;
412423
}
413424

414425
return ok ? 0 : 1;
415426
}
427+
#endif

algorithms/arithmetic/go/arithmetic.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"fmt"
88
"io"
99
"os"
10+
11+
"github.com/LessUp/compress-kit/algorithms/shared/go/codec"
1012
)
1113

1214
const (
@@ -415,12 +417,17 @@ func Decode(r io.Reader, w io.Writer) error {
415417
bw := bufio.NewWriter(w)
416418
bitReader := NewBitReader(br)
417419
decoder := NewArithmeticDecoder(bitReader)
420+
var totalWritten uint64
418421

419422
for {
420423
sym := decoder.DecodeSymbol(cumulative)
421424
if sym == uint32(EOFSymbol) {
422425
break
423426
}
427+
totalWritten++
428+
if totalWritten > codec.MaxOutputSize {
429+
return fmt.Errorf("output size limit exceeded")
430+
}
424431
if err := bw.WriteByte(byte(sym)); err != nil {
425432
return err
426433
}
@@ -431,34 +438,38 @@ func Decode(r io.Reader, w io.Writer) error {
431438

432439
// EncodeFile is a convenience function for file-based encoding.
433440
func EncodeFile(inputPath, outputPath string) error {
434-
in, err := os.Open(inputPath)
441+
input, err := os.ReadFile(inputPath)
435442
if err != nil {
436443
return fmt.Errorf("cannot open input file: %s: %w", inputPath, err)
437444
}
438-
defer in.Close()
439445

440-
out, err := os.Create(outputPath)
446+
encoded, err := codec.EncodeBuffer(NewStreamingEncoder(), input)
441447
if err != nil {
448+
return err
449+
}
450+
451+
if err := os.WriteFile(outputPath, encoded, 0o644); err != nil {
442452
return fmt.Errorf("cannot open output file: %s: %w", outputPath, err)
443453
}
444-
defer out.Close()
445454

446-
return Encode(in, out)
455+
return nil
447456
}
448457

449458
// DecodeFile is a convenience function for file-based decoding.
450459
func DecodeFile(inputPath, outputPath string) error {
451-
in, err := os.Open(inputPath)
460+
input, err := os.ReadFile(inputPath)
452461
if err != nil {
453462
return fmt.Errorf("cannot open input file: %s: %w", inputPath, err)
454463
}
455-
defer in.Close()
456464

457-
out, err := os.Create(outputPath)
465+
decoded, err := codec.DecodeBuffer(NewStreamingDecoder(), input)
458466
if err != nil {
467+
return err
468+
}
469+
470+
if err := os.WriteFile(outputPath, decoded, 0o644); err != nil {
459471
return fmt.Errorf("cannot open output file: %s: %w", outputPath, err)
460472
}
461-
defer out.Close()
462473

463-
return Decode(in, out)
474+
return nil
464475
}

0 commit comments

Comments
 (0)