{"id":33939616,"url":"https://github.com/najamelan/futures_ringbuf","last_synced_at":"2025-12-12T15:41:39.309Z","repository":{"id":57632663,"uuid":"202219217","full_name":"najamelan/futures_ringbuf","owner":"najamelan","description":"Fake network stream for testing and examples without having to do TCP","archived":false,"fork":false,"pushed_at":"2023-06-04T15:08:08.000Z","size":115,"stargazers_count":13,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"dev","last_synced_at":"2025-10-29T12:26:10.821Z","etag":null,"topics":["async","crate","networking","rust","testing"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/najamelan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/funding.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"liberapay":"najamelan"}},"created_at":"2019-08-13T20:30:19.000Z","updated_at":"2023-04-11T18:57:40.000Z","dependencies_parsed_at":"2023-01-23T17:45:18.168Z","dependency_job_id":null,"html_url":"https://github.com/najamelan/futures_ringbuf","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/najamelan/futures_ringbuf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/najamelan%2Ffutures_ringbuf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/najamelan%2Ffutures_ringbuf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/najamelan%2Ffutures_ringbuf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/najamelan%2Ffutures_ringbuf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/najamelan","download_url":"https://codeload.github.com/najamelan/futures_ringbuf/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/najamelan%2Ffutures_ringbuf/sbom","scorecard":{"id":673155,"data":{"date":"2025-08-11","repo":{"name":"github.com/najamelan/futures_ringbuf","commit":"78ebf561ab1663455c19bab6a464b56a9d230a2b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":1,"reason":"Found 4/26 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/najamelan/futures_ringbuf/ci.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/najamelan/futures_ringbuf/ci.yml/dev?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/najamelan/futures_ringbuf/ci.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/najamelan/futures_ringbuf/ci.yml/dev?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:60: update your workflow using https://app.stepsecurity.io/secureworkflow/najamelan/futures_ringbuf/ci.yml/dev?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:71: update your workflow using https://app.stepsecurity.io/secureworkflow/najamelan/futures_ringbuf/ci.yml/dev?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:75: update your workflow using https://app.stepsecurity.io/secureworkflow/najamelan/futures_ringbuf/ci.yml/dev?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:84: update your workflow using https://app.stepsecurity.io/secureworkflow/najamelan/futures_ringbuf/ci.yml/dev?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   6 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: The Unlicense: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'dev'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T20:49:11.471Z","repository_id":57632663,"created_at":"2025-08-21T20:49:11.471Z","updated_at":"2025-08-21T20:49:11.471Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27515340,"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-12-05T02:00:07.920Z","response_time":54,"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":["async","crate","networking","rust","testing"],"created_at":"2025-12-12T15:41:34.842Z","updated_at":"2025-12-12T15:41:39.303Z","avatar_url":"https://github.com/najamelan.png","language":"Rust","funding_links":["https://liberapay.com/najamelan"],"categories":[],"sub_categories":[],"readme":"# futures_ringbuf\n\n[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)\n[![Build Status](https://api.travis-ci.org/najamelan/futures_ringbuf.svg?branch=master)](https://travis-ci.org/najamelan/futures_ringbuf)\n[![Docs](https://docs.rs/futures_ringbuf/badge.svg)](https://docs.rs/futures_ringbuf)\n[![crates.io](https://img.shields.io/crates/v/futures_ringbuf.svg)](https://crates.io/crates/futures_ringbuf)\n\n\n\u003e A ringbuffer that implements AsyncRead/AsyncWrite.\n\nIt can be used for testing async network crates cross-platform without having to make TCP connections. The crate provides a type `Endpoint` which allows creating both ends of a fake network stream with a ringbuffer in each direction.\nIt facilitates testing more complex situations like back pressure.\n\nIt can also be used as an in memory buffer for communicating between async tasks. I haven't done benchmarks yet.\n\nThere are currently 2 versions of the AsyncRead/Write traits. The _futures-rs_ version and the _tokio_ version. This crate implements the futures version. You can get the tokio version by using [`tokio_util::compat`](https://docs.rs/tokio-util/latest/tokio_util/compat/index.html).\n\nData in transit is held in an internal RingBuffer from the [ringbuf crate](https://crates.io/crates/ringbuf).\n\nWhen the `sketchy` feature is enabled, a type [`Sketchy`] is available that randomizes the behavior of the in memory buffers which would otherwise always be ready which isn't very realistic for testing code that will run against actual network connections later. This will randomly return pending and fill only partial buffers.\n\n## Table of Contents\n\n- [Install](#install)\n   - [Upgrade](#upgrade)\n   - [Dependencies](#dependencies)\n- [Security](#security)\n- [Usage](#usage)\n   - [WASM](#wasm)\n   - [Basic Example](#basic-example)\n   - [Endpoint Example](#endpoint-example)\n- [API](#api)\n- [Contributing](#contributing)\n   - [Code of Conduct](#code-of-conduct)\n- [License](#license)\n\n\n## Install\nWith [cargo add](https://github.com/killercup/cargo-edit):\n`cargo add futures_ringbuf`\n\nWith [cargo yaml](https://gitlab.com/storedbox/cargo-yaml):\n```yaml\ndependencies:\n\n   futures_ringbuf: ^0.4\n```\n\nWith raw Cargo.toml\n```toml\n[dependencies]\n\n    futures_ringbuf = \"^0.4\"\n```\n\n### Upgrade\n\nPlease check out the [changelog](https://github.com/najamelan/futures_ringbuf/blob/master/CHANGELOG.md) when upgrading.\n\n\n### Dependencies\n\nThis crate has few dependencies. Cargo will automatically handle its dependencies for you.\n\n### Features\n\nThe `sketchy` feature will turn on the `Sketchy` type which allows randomly changing the behavior of an async stream to enable testing situations that occur on an actual network like timing out, processing only partial buffers, pending, ...\n\n## Security\n\nThis crate uses `#![ forbid(unsafe_code) ]`, but it's dependencies use quite some unsafe. On first sight the unsafe usage in `ringbuf` looks sound, but I haven't scrutinized every detail of it and it's not documented.\nA lot of unsafe code is present in the futures library, which I haven't reviewed.\n\n\n## Usage\n\nThe crate provides a `RingBuffer\u003cT\u003e` struct which implements `AsyncRead`/`AsyncWrite` from the futures library\nwhen `T` is u8. You can now call `split` provided by `AsyncRead` and treat them as both ends of a network connection.\n\nThe reader will return `Poll::Pending` when the buffer is empty, and the writer when the buffer is full. They will\nwake each other up when new data/space is available.\n\nIf you want to play with `std::io::Read`/`std::io::Write`, check out the `ringbuf` crate directly, as it's `Producer` and\n`Consumer` types implement these traits, so I didn't include them here.\n\nI haven't yet included `Stream\u003cT\u003e`, `Sink\u003cT\u003e`, because on `u8` that doesn't make much sense, but if there is demand,\nit can definitely be added.\n\nThe requirements on `T` are `T: Sized + Copy`.\n\nIf you want to seed the buffer before using it with futures_ringbuf, you can use the `Producer` and `Consumer` types of ringbuf. `futures_ringbuf::RingBuffer` implements `From\u003c (Producer\u003cT\u003e, Consumer\u003cT\u003e) \u003e`.\n\n\n### WASM\n\nThis crate works on WASM. See the [integration test](https://github.com/najamelan/futures_ringbuf/tree/master/test/wasm.rs) for some code.\n\n\n### Basic example\n\n```rust\n//! Frame a RingBuf with futures_codec. This example shows how the sending task will\n//! block when the buffer is full. When a reader consumes the buffer, the sender is woken up.\n//!\n//! Run with `cargo run --example basic`.\n//\nuse\n{\n   futures_ringbuf    :: { *                                            } ,\n   futures            :: { SinkExt, StreamExt, executor::block_on, join } ,\n   asynchronous_codec :: { Framed, LinesCodec                           } ,\n};\n\n\n#[ async_std::main ]\n//\nasync fn main()\n{\n   let mock = RingBuffer::new( 13 );\n   let (mut writer, mut reader) = Framed::new( mock, LinesCodec{} ).split();\n\n\n   let send_task = async move\n   {\n      writer.send( \"Hello World\\n\".to_string() ).await.expect( \"send\" );\n      println!( \"sent first line\" );\n\n      writer.send( \"Second line\\n\".to_string() ).await.expect( \"send\" );\n      println!( \"sent second line\" );\n\n      writer.close().await.expect( \"close sender\" );\n      println!( \"sink closed\" );\n   };\n\n\n   let receive_task = async move\n   {\n      // If we would return here, the second line will never get sent\n      // because the buffer is full.\n      //\n      // return;\n\n      while let Some(msg) = reader.next().await.transpose().expect( \"receive message\" )\n      {\n         println!( \"Received: {:#?}\", msg );\n      }\n   };\n\n\n   // Poll them in concurrently\n   //\n   join!( send_task, receive_task );\n}\n```\n\n\n### Endpoint\n\nWhen using one ringbuffer, we get both ends of one connection. If we want a more realistic duplex connection, we\nneed two ringbuffers, with one endpoint reading from the ringbuffer the other endpoint is writing to. Tasks need\nto be woken up correctly when new data or space becomes available... To facilitate this, an `Endpoint` type is provided which will take care of this setup for you.\n\n\n### Endpoint example\n\n```rust\nuse\n{\n   futures_ringbuf :: { *                                               } ,\n   futures         :: { AsyncWriteExt, AsyncReadExt, executor::block_on } ,\n};\n\n\n#[ async_std::main ]\n//\nasync fn main()\n{\n   // Buffer of 10 bytes in each direction. The buffer size always refers to the writing side, so here\n   // the first 10 means the server can write 10 bytes before it's buffer is full.\n   // When it's full it will return pending on writing and when it's empty it returns\n   // pending on reading.\n   //\n   let (mut server, mut client) = Endpoint::pair( 10, 10 );\n\n   let     data = vec![ 1,2,3 ];\n   let mut read = [0u8;3];\n\n   server.write( \u0026data ).await.expect( \"write\" );\n\n   let n = client.read( \u0026mut read ).await.expect( \"read\" );\n\n   assert_eq!( n   , 3                 );\n   assert_eq!( read, vec![ 1,2,3 ][..] );\n}\n```\n\n\n## API\n\nAPI documentation can be found on [docs.rs](https://docs.rs/futures_ringbuf).\n\n\n## Contributing\n\nPlease check out the [contribution guidelines](https://github.com/najamelan/futures_ringbuf/blob/master/CONTRIBUTING.md).\n\n\n### Testing\n\n`cargo test`\n\nOn WASM, after [installing wasm-pack](https://rustwasm.github.io/wasm-pack/):\n\n`wasm-pack test --firefox --headless`\n\nor\n\n`wasm-pack test --chrome --headless`\n\n### Code of conduct\n\nAny of the behaviors described in [point 4 \"Unacceptable Behavior\" of the Citizens Code of Conduct](http://citizencodeofconduct.org/#unacceptable-behavior) are not welcome here and might get you banned. If anyone including maintainers and moderators of the project fail to respect these/your limits, you are entitled to call them out.\n\n## License\n\n[Unlicence](https://unlicense.org/)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnajamelan%2Ffutures_ringbuf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnajamelan%2Ffutures_ringbuf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnajamelan%2Ffutures_ringbuf/lists"}