Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Rust

on: [push, pull_request]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./rust

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- name: Cache cargo
uses: Swatinem/rust-cache@v2
with:
workspaces: rust

- name: Check Formatting
run: cargo fmt --check

- name: Clippy
run: cargo clippy --all-targets -- -D warnings

- name: Test
run: cargo test

- name: Build CLI
run: cargo build --features cli
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ __pycache__
# Go artifacts
*.test
*.out

# Bench fixtures
test/.bench-circular.flatted.json
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Available also for **[Python](./python/flatted.py)**.

Available also for **[Go](./golang/README.md)**.

Available also for **[Rust](./rust/README.md)**.

- - -

## ℹ️ JSON only values
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
"test": "c8 node test/index.js",
"test:php": "php php/test.php",
"test:py": "python python/test.py",
"test:rs": "cargo test --manifest-path rust/Cargo.toml",
"bench:js-rs": "node test/bench-js-vs-rs.mjs",
"ts": "tsc -p .",
"coverage": "mkdir -p ./coverage; c8 report --reporter=text-lcov > ./coverage/lcov.info"
},
Expand All @@ -34,6 +36,7 @@
"php/flatted.php",
"python/flatted.py",
"golang/pkg/flatted/flatted.go",
"rust/src/lib.rs",
"types/"
],
"keywords": [
Expand Down
3 changes: 3 additions & 0 deletions rust/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target
/Cargo.lock
/flatted
31 changes: 31 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "flatted"
version = "0.1.0"
edition = "2021"
rust-version = "1.70"
authors = ["Andrea Giammarchi"]
license = "ISC"
description = "A super light and fast circular JSON parser."
repository = "https://github.com/WebReflection/flatted"
homepage = "https://github.com/WebReflection/flatted"
readme = "README.md"
keywords = ["circular", "json", "parser", "serialize", "flatted"]
categories = ["encoding", "parser-implementations"]
exclude = ["target/"]

[dependencies]
indexmap = "2"
serde_json = { version = "1", default-features = false, features = ["std", "preserve_order"] }

[lib]
name = "flatted"
path = "src/lib.rs"

[[bin]]
name = "flatted"
path = "src/main.rs"
required-features = ["cli"]

[features]
default = []
cli = []
20 changes: 20 additions & 0 deletions rust/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
BINARY_NAME=flatted

.PHONY: build test lint check clean

build:
cargo build --release --features cli
cp target/release/$(BINARY_NAME) ./$(BINARY_NAME)

test:
cargo test

lint:
cargo fmt --check
cargo clippy --all-targets -- -D warnings

check: test lint

clean:
cargo clean
rm -f $(BINARY_NAME)
83 changes: 83 additions & 0 deletions rust/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# flatted (Rust)

A super light and fast circular JSON parser.

## Usage

```toml
[dependencies]
flatted = { path = "../rust" } # or publish path / git dependency
```

```rust
use std::cell::RefCell;
use std::rc::Rc;

use flatted::{parse_simple, stringify_simple, Object, Value};

fn main() {
// const a = [{}]; a[0].a = a; a.push(a);
let a = Value::Array(Rc::new(RefCell::new(vec![Value::empty_object()])));
let first = a.as_array().unwrap().borrow()[0].clone();
first
.as_object()
.unwrap()
.borrow_mut()
.insert("a".into(), a.clone());
a.as_array().unwrap().borrow_mut().push(a.clone());

let s = stringify_simple(&a).unwrap();
assert_eq!(s, r#"[["1","0"],{"a":"0"}]"#);

let back = parse_simple(&s).unwrap();
let again = back.as_array().unwrap().borrow()[1].clone();
let self_ref = again.as_object().unwrap().borrow().get("a").cloned().unwrap();
assert!(back.ptr_eq(&self_ref));
}
```

Arrays and objects use `Rc<RefCell<_>>` so circular and shared references keep
their identity after parsing (Rust has no built-in reference-typed JSON value).

## API

| Function | Role |
|----------|------|
| `stringify(value, replacer, space)` | Flatten to flatted JSON text |
| `parse(text, reviver)` | Restore a recursive value graph |
| `to_json(value)` | Flatten to a plain `serde_json::Value` array |
| `from_json(value)` | Restore recursion from that array |
| `stringify_simple` / `parse_simple` | Same without replacer/reviver/space |

## CLI

```bash
cargo build --release --features cli
echo '{"a":"b"}' | ./target/release/flatted
echo '[{"a":"1"},"b"]' | ./target/release/flatted -d
```

## Test

```bash
cargo test
```

## Bench (vs JS)

Same 1s wall-clock methodology as `test/bench.js`:

```bash
# from repo root — compares ESM/JS vs Rust release
npm run bench:js-rs

# or individually
node test/bench-flatted.mjs
cargo run --example bench --release --manifest-path rust/Cargo.toml
```

## Note on crates.io

The name `flatted` is already taken on crates.io by an unofficial port. This
directory is the official WebReflection port in this repository; publish naming
can be decided separately (for example a scoped / renamed crate).
Loading
Loading