{"id":30141836,"url":"https://github.com/aspadax/surfing","last_synced_at":"2026-04-09T14:03:42.705Z","repository":{"id":294601232,"uuid":"987454023","full_name":"AspadaX/surfing","owner":"AspadaX","description":"A Rust library for parsing JSON objects from text streams.","archived":false,"fork":false,"pushed_at":"2025-05-26T02:14:41.000Z","size":67,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-08T18:11:29.493Z","etag":null,"topics":["ai","gpt","json","llm","parser","rust","serde","serde-json"],"latest_commit_sha":null,"homepage":"https://github.com/AspadaX/surfing","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AspadaX.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-21T05:20:30.000Z","updated_at":"2025-07-21T02:59:03.000Z","dependencies_parsed_at":"2025-05-21T07:55:09.432Z","dependency_job_id":null,"html_url":"https://github.com/AspadaX/surfing","commit_stats":null,"previous_names":["aspadax/surfing"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/AspadaX/surfing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AspadaX%2Fsurfing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AspadaX%2Fsurfing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AspadaX%2Fsurfing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AspadaX%2Fsurfing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AspadaX","download_url":"https://codeload.github.com/AspadaX/surfing/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AspadaX%2Fsurfing/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269833310,"owners_count":24482423,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-11T02:00:10.019Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","gpt","json","llm","parser","rust","serde","serde-json"],"created_at":"2025-08-11T05:19:16.142Z","updated_at":"2026-04-09T14:03:42.660Z","avatar_url":"https://github.com/AspadaX.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Surfing 🏄\n\nA Rust library for parsing JSON objects from text streams.\n\n[![Crates.io](https://img.shields.io/crates/v/surfing.svg)](https://crates.io/crates/surfing)\n[![Documentation](https://docs.rs/surfing/badge.svg)](https://docs.rs/surfing)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## What is Surfing?\n\nSurfing is a lightweight Rust library that extracts JSON objects from mixed text content. \n\n## Real-world Use Cases\n\n### Extracting Structured Data from LLM Outputs\n\nLarge Language Models often output JSON mixed with explanatory text, and reasoning models may output jsons with their reasoning steps. Surfing makes it easy to extract and use this structured data:\n\n```rust\nuse std::io::stdout;\nuse surfing::JSONParser;\n\n// Process LLM response containing JSON\nlet llm_response = \"Here's the user profile: {\\\"id\\\":123,\\\"name\\\":\\\"Alice\\\",\\\"role\\\":\\\"admin\\\"} Let me know if you need more info.\";\n\nlet mut parser = JSONParser::new();\nlet mut lock = stdout().lock();\n\n// Extract only the JSON part\nparser.extract_json_from_stream(\u0026mut lock, llm_response).unwrap();\n// Output: {\"id\":123,\"name\":\"Alice\",\"role\":\"admin\"}\n```\n\n### Processing Streaming LLM Responses\n\nWhen working with streaming API responses, JSON often arrives in chunks. Surfing handles this seamlessly:\n\n```rust\nuse std::io::stdout;\nuse surfing::JSONParser;\n\n// Initialize the parser\nlet mut json_parser = JSONParser::new();\nlet mut lock = stdout().lock();\n\n// Process each chunk as it arrives from a streaming API\nlet chunks = [\n    \"The weather forecast is {\\\"location\\\":\\\"New York\\\",\",\n    \"\\\"temperature\\\":72,\\\"conditions\\\":\\\"sunny\\\"}\",\n    \" Hope that helps!\"\n];\n\nfor chunk in chunks {\n    json_parser.extract_json_from_stream(\u0026mut lock, chunk).unwrap();\n}\n// Outputs: {\"location\":\"New York\",\"temperature\":72,\"conditions\":\"sunny\"}\n```\n\n### Deserializing JSON Directly into Rust Structs\n\nWith the `serde` feature enabled, you can directly extract and deserialize JSON into your data structures:\n\n```rust\nuse serde::Deserialize;\nuse surfing::serde::StreamingDeserializer;\n\n#[derive(Debug, Deserialize)]\nstruct Weather {\n    location: String,\n    temperature: i32,\n    conditions: String,\n}\n\n// Create a deserializer for Weather structs\nlet mut deserializer = StreamingDeserializer::\u003cWeather\u003e::new();\n\n// Process chunks as they arrive\nlet chunks = [\n    \"The weather forecast is {\\\"location\\\":\\\"New York\\\",\",\n    \"\\\"temperature\\\":72,\\\"conditions\\\":\\\"sunny\\\"} Hope that helps!\"\n];\n\nfor chunk in chunks {\n    let result = deserializer.process_chunk(chunk).unwrap();\n    if let Some(weather) = result {\n        println!(\"Weather in {}: {}°F, {}\", \n            weather.location, \n            weather.temperature,\n            weather.conditions);\n    }\n}\n\n// Output: Weather in New York: 72°F, sunny\n```\n\n### Processing Log Files with Embedded JSON\n\nMany modern logging systems emit JSON data. Surfing helps extract and analyze this data:\n\n```rust\nuse std::io::BufWriter;\nuse surfing::JSONParser;\n\n// Log entries with embedded JSON\nlet log_entries = r#\"\n[2023-06-15 14:30:00] INFO: System starting\n[2023-06-15 14:30:01] DEBUG: {\"component\":\"database\",\"status\":\"connected\",\"latency_ms\":45}\n[2023-06-15 14:30:05] ERROR: {\"error\":\"connection_timeout\",\"service\":\"auth\",\"attempts\":3}\n[2023-06-15 14:30:10] INFO: System ready\n\"#;\n\nlet mut parser = JSONParser::new();\nlet mut buffer = Vec::new();\n{\n    let mut writer = BufWriter::new(\u0026mut buffer);\n    parser.extract_json_from_stream(\u0026mut writer, log_entries).unwrap();\n}\n\nlet json_only = String::from_utf8(buffer).unwrap();\nprintln!(\"{}\", json_only);\n// Output:\n// {\"component\":\"database\",\"status\":\"connected\",\"latency_ms\":45}\n// {\"error\":\"connection_timeout\",\"service\":\"auth\",\"attempts\":3}\n```\n\n## Installation\n\nAdd `surfing` to your project:\n\n```bash\ncargo add surfing\n```\n\nOr with serde support:\n\n```bash\ncargo add surfing --features serde\n```\n\n## How It Works\n\nSurfing works by:\n\n1. Watching for JSON opening markers (`{` or `[`)\n2. Tracking nested JSON structures\n3. Writing only the JSON content to your output\n4. Resetting state when complete JSON objects are found\n\nThe parser is stateful, so it can handle JSON objects split across multiple chunks.\n\n## Key Advantages\n\n- **Zero external dependencies** in the core library\n- **Streaming-friendly** for processing large files or API responses\n- **Memory-efficient** with minimal state tracking\n- **Serde integration** for direct deserialization (optional)\n- **Simple API** with both high and low-level options\n\n## Learn More\n\nCheck out the examples directory for more use cases:\n\n- `openai_json_extraction.rs` - Extracting JSON from OpenAI API responses\n- `basic.rs` - Simple extraction from mixed text\n- `streaming.rs` - Processing data in chunks\n- `stdout.rs` - Filtering JSON to standard output\n\n## License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faspadax%2Fsurfing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faspadax%2Fsurfing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faspadax%2Fsurfing/lists"}