{"id":13414709,"url":"https://github.com/P3KI/bendy","last_synced_at":"2025-03-14T22:32:03.370Z","repository":{"id":47366876,"uuid":"142165019","full_name":"P3KI/bendy","owner":"P3KI","description":"A rust library for encoding and decoding bencode with enforced cannonicalization rules.","archived":false,"fork":false,"pushed_at":"2023-08-14T10:55:03.000Z","size":290,"stargazers_count":74,"open_issues_count":14,"forks_count":13,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-09-17T09:39:23.718Z","etag":null,"topics":["bencode","decoding","encoding","hacktoberfest"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/P3KI.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-BSD3","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-07-24T13:49:40.000Z","updated_at":"2024-09-05T06:57:34.000Z","dependencies_parsed_at":"2024-01-15T23:26:53.331Z","dependency_job_id":"53cd57dc-e5e4-47f7-8e97-c3f2b527f9e3","html_url":"https://github.com/P3KI/bendy","commit_stats":{"total_commits":175,"total_committers":8,"mean_commits":21.875,"dds":0.6342857142857143,"last_synced_commit":"914792ab63509c0a5f45a3aad3fa157a0b25849a"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P3KI%2Fbendy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P3KI%2Fbendy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P3KI%2Fbendy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P3KI%2Fbendy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/P3KI","download_url":"https://codeload.github.com/P3KI/bendy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243658055,"owners_count":20326459,"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","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":["bencode","decoding","encoding","hacktoberfest"],"created_at":"2024-07-30T21:00:33.550Z","updated_at":"2025-03-14T22:32:02.949Z","avatar_url":"https://github.com/P3KI.png","language":"Rust","readme":"# Bendy\n\n[![Build Status](https://travis-ci.org/P3KI/bendy.svg?branch=master)](https://travis-ci.org/P3KI/bendy)\n[![Current Version](https://meritbadge.herokuapp.com/bendy)](https://crates.io/crates/bendy)\n[![License: BSD-3-Clause](https://img.shields.io/github/license/P3KI/bendy.svg)](https://github.com/P3KI/bendy/blob/master/LICENSE-BSD3)\n\nA Rust library for encoding and decoding bencode with enforced canonicalization rules.\n[Bencode](https://en.wikipedia.org/wiki/Bencode) is a simple but very effective encoding\nscheme, originating with the BitTorrent peer-to-peer system.\n\n---\n\nYou may be looking for:\n\n- [Known Alternatives](#known-alternatives)\n- [Why should I use it](#why-should-i-use-it)\n- [Usage](#usage)\n - [Encoding](#encoding-with-tobencode)\n - [Decoding](#decoding-with-frombencode)\n- [Unsafe Code](#usage-of-unsafe-code)\n- [Contributing](#contributing)\n\n---\n\n## Known alternatives:\nThis is not the first library to implement Bencode. In fact there's several\nimplementations already:\n\n- Toby Padilla [serde-bencode](https://github.com/toby/serde-bencode)\n- Arjan Topolovec's [rust-bencode](https://github.com/arjantop/rust-bencode),\n- Murarth's [bencode](https://github.com/murarth/bencode),\n- and Jonas Hermsmeier's [rust-bencode](https://github.com/jhermsmeier/rust-bencode)\n\n## Why should I use it?\nSo why the extra work adding yet-another-version of a thing that already exists, you\nmight ask?\n\n### Enforced correctness\nImplementing a canonical encoding form is straight forward. It comes down to defining\n*a proper way of handling unordered data*. The next step is that bendy's sorting data\nbefore encoding it using the regular Bencode rules. If your data is already sorted bendy\nwill of course skip the extra sorting step to gain efficiency.\nBut bendy goes a step further to *ensure correctness*: If you hand the library data that\nyou say is already sorted, bendy still does an in-place verification to *ensure that your\ndata actually is sorted* and complains if it isn't. In the end, once bendy serialized\nyour data, it's Bencode through and through. So it's perfectly compatible with every\nother Bencode library.\n\nJust remember: At this point *only bendy* enforces the correctness of the canonical\nformat if you read it back in.\n\n### Canonical representation\nBendy ensures that any de-serialize / serialize round trip produces the exact *same*\nand *correct* binary representation. This is relevant if you're dealing with unordered\nsets or map-structured data where theoretically the order is not relevant, but in\npractice it is, especially if you want to ensure that cryptographic signatures related\nto the data structure do not get invalidated accidentally.\n\n| Data Structure | Default Impl | Comment                                                                                    |\n|----------------|--------------|--------------------------------------------------------------------------------------------|\n| Vec            | ✔            | Defines own ordering                                                                       |\n| VecDeque       | ✔            | Defines own ordering                                                                       |\n| LinkedList     | ✔            | Defines own ordering                                                                       |\n| HashMap        | ✔            | Ordering missing but content is ordered by key byte representation.                        |\n| BTreeMap       | ✔            | Defines own ordering                                                                       |\n| HashSet        | ✘            | (Unordered) Set handling not yet defined                                                   |\n| BTreeSet       | ✘            | (Unordered) Set handling not yet defined                                                   |\n| BinaryHeap     | ✘            | Ordering missing                                                                           |\n| Iterator       | ~            | `emit_unchecked_list()` allows to emit any iterable but user needs to ensure the ordering. |\n\n**Attention:**\n\n- Since most list types already define their inner ordering, data structures\n  like `Vec`, `VecDeque`, and `LinkedList` will not get sorted during encoding!\n\n- There is no default implementation for handling generic iterators.\n  This is by design. `Bendy` cannot tell from an iterator whether the underlying\n  structure requires sorting or not and would have to take data as-is.\n\n## Usage\n\nFirst you need to add bendy as a project dependency:\n\n```toml\n[dependencies]\nbendy = \"^0.3\"\n```\n\n### Encoding with `ToBencode`\n\nTo encode an object of a type which already implements the `ToBencode` trait\nit is enough to import the trait and call the `to_bencode()` function on the object.\n\n```rust\nuse bendy::encoding::{ToBencode, Error};\n\nlet my_data = vec![\"hello\", \"world\"];\nlet encoded = my_data.to_bencode()?;\n\nassert_eq!(b\"l5:hello5:worlde\", encoded.as_slice());\n\nOk::\u003c(), Error\u003e(())\n```\n\n### Implementing `ToBencode`\n\nIn most cases it should be enough to overwrite the associated `encode` function\nand keep the default implementation of `to_bencode`.\n\nThe function will provide you with a `SingleItemEncoder` which must be used to\nemit any relevant components of the current object. As long as these implement\n`ToBencode` themselves it is enough to pass them into the `emit` function of\nthe encoder as this will serialize any type implementing the trait.\n\nNext to `emit` the encoder also provides a list of functions to encode specific\nbencode primitives (i.e. `emit_int` and `emit_str`) and nested bencode elements\n(i.e. `emit_dict` and `emit_list`). These methods should be used if its necessary\nto output a specific non default data type.\n\n**Implementing Integer Encoding**\n\nAs bencode has native integer support bendy provides default implementations for\nall of rusts native integer types. This allows to call `to_bencode` on any integer\nobject and to pass these objects into the encoder's `emit_int` function.\n\n```rust\nuse bendy::encoding::{ToBencode, SingleItemEncoder, Error};\n\nstruct IntegerWrapper(i64);\n\nimpl ToBencode for IntegerWrapper {\n    const MAX_DEPTH: usize = 0;\n\n    fn encode(\u0026self, encoder: SingleItemEncoder) -\u003e Result\u003c(), Error\u003e {\n        encoder.emit_int(self.0)\n    }\n}\n\nlet example = IntegerWrapper(21);\n\nlet encoded = example.to_bencode()?;\nassert_eq!(b\"i21e\", encoded.as_slice());\n\nlet encoded = 21.to_bencode()?;\nassert_eq!(b\"i21e\", encoded.as_slice());\n\nOk::\u003c(), Error\u003e(())\n```\n\n**Encode a byte string**\n\nAnother data type bencode natively supports are byte strings. Therefore bendy\nprovides default implementations for `String` and `\u0026str`.\n\n```rust\nuse bendy::encoding::{ToBencode, SingleItemEncoder, Error};\n\nstruct StringWrapper(String);\n\nimpl ToBencode for StringWrapper {\n    const MAX_DEPTH: usize = 0;\n\n    fn encode(\u0026self, encoder: SingleItemEncoder) -\u003e Result\u003c(), Error\u003e {\n        encoder.emit_str(\u0026self.0)\n    }\n}\n\nlet example = StringWrapper(\"content\".to_string());\n\nlet encoded = example.to_bencode()?;\nassert_eq!(b\"7:content\", encoded.as_slice());\n\nlet encoded = \"content\".to_bencode()?;\nassert_eq!(b\"7:content\", encoded.as_slice());\n\nOk::\u003c(), Error\u003e(())\n```\n\nAs its a very common pattern to represent a byte string as `Vec\u003cu8\u003e` bendy\nexposes the `AsString` wrapper. This can be used to encapsulate any element\nimplementing `AsRef\u003c[u8]\u003e` to output itself as a bencode string instead of a\nlist.\n\n```rust\nuse bendy::encoding::{ToBencode, SingleItemEncoder, Error, AsString};\n\nstruct ByteStringWrapper(Vec\u003cu8\u003e);\n\nimpl ToBencode for ByteStringWrapper {\n    const MAX_DEPTH: usize = 0;\n\n    fn encode(\u0026self, encoder: SingleItemEncoder) -\u003e Result\u003c(), Error\u003e {\n        let content = AsString(\u0026self.0);\n        encoder.emit(\u0026content)\n    }\n}\n\nlet example = ByteStringWrapper(b\"content\".to_vec());\n\nlet encoded = example.to_bencode()?;\nassert_eq!(b\"7:content\", encoded.as_slice());\n\nlet encoded = AsString(b\"content\").to_bencode()?;\nassert_eq!(b\"7:content\", encoded.as_slice());\n\nOk::\u003c(), Error\u003e(())\n```\n\n**Encode a dictionary**\n\nIf a data structure contains key-value pairs its most likely a good idea to\nencode it as a bencode dictionary. This is also true for most structs with\nmore then one member as it might be helpful to represent their names to ensure\nthe existence of specific (optional) member.\n\n__Attention:__ To ensure a canonical representation bendy requires that the keys\nof a dictionary emitted via `emit_dict` are sorted in ascending order or the\nencoding will fail with an error of kind `UnsortedKeys`. In case of an unsorted\ndictionary it might be useful to use `emit_and_sort_dict` instead.\n\n```rust\nuse bendy::encoding::{ToBencode, SingleItemEncoder, Error};\n\nstruct Example {\n    label: String,\n    counter: u64,\n}\n\nimpl ToBencode for Example {\n    const MAX_DEPTH: usize = 1;\n\n    fn encode(\u0026self, encoder: SingleItemEncoder) -\u003e Result\u003c(), Error\u003e {\n        encoder.emit_dict(|mut e| {\n            e.emit_pair(b\"counter\", \u0026self.counter)?;\n            e.emit_pair(b\"label\", \u0026self.label)?;\n\n            Ok(())\n        })\n    }\n}\n\nlet example = Example { label: \"Example\".to_string(), counter: 0 };\n\nlet encoded = example.to_bencode()?;\nassert_eq!(b\"d7:counteri0e5:label7:Examplee\", encoded.as_slice());\n\nOk::\u003c(), Error\u003e(())\n```\n\n**Encode a list**\n\nWhile encoding a list bendy assumes the elements inside this list are\ninherently sorted through their position inside the list. The implementation\nis therefore free to choose its own sorting.\n\n```rust\nuse bendy::encoding::{ToBencode, SingleItemEncoder, Error};\n\nstruct Location(i64, i64);\n\nimpl ToBencode for Location {\n    const MAX_DEPTH: usize = 1;\n\n    fn encode(\u0026self, encoder: SingleItemEncoder) -\u003e Result\u003c(), Error\u003e {\n        encoder.emit_list(|e| {\n            e.emit_int(self.0)?;\n            e.emit_int(self.1)\n        })\n    }\n}\n\nlet example = Location(2, 3);\n\nlet encoded = example.to_bencode()?;\nassert_eq!(b\"li2ei3ee\", encoded.as_slice());\n\nOk::\u003c(), Error\u003e(())\n```\n\n### Decoding with `FromBencode`\n\nTo decode an object of a type which already implements the `FromBencode` trait\nit is enough to import the trait and call the `from_bencode()` function on the object.\n\n```rust\nuse bendy::decoding::{FromBencode, Error};\n\nlet encoded = b\"l5:hello5:worlde\".to_vec();\nlet decoded = Vec::\u003cString\u003e::from_bencode(\u0026encoded)?;\n\nassert_eq!(vec![\"hello\", \"world\"], decoded);\n\nOk::\u003c(), Error\u003e(())\n```\n\n### Implementing `FromBencode`\n\nIn most cases it should be enough to overwrite the associated\n`decode_bencode_object` function and keep the default implementation of\n`from_bencode`.\n\nThe function will provide you with an representation of a bencode `Object`\nwhich must be processed to receive any relevant components of the expected data\ntype. As long as these implement `FromBencode` themselves it is enough to call\n`decode_bencode_object` on the expected data type of the element as this will\ndeserialize any type implementing the trait.\n\nNext to `from_bencode` the bencode `Object` representation also provides a list\nof helper functions to itself into specific bencode primitives and container\n(i.e. `bytes_or`, `integer_or_else` or `try_into_list`). Which than can be used\nto restore the actual element.\n\n**Decode an integer**\n\nAs bencode has native integer support bendy provides default implementations\nfor all of rusts native integer types. This allows to call `from_bencode` on\nany type of integer.\n\n*Attention:* If it's necessary to handle a big integer which has no\nrepresentation through one of the default data types it's always possible to\naccess the string version of the number during decoding.\n\n```rust\nuse bendy::decoding::{FromBencode, Object, Error};\n\n#[derive(Debug, Eq, PartialEq)]\nstruct IntegerWrapper(i64);\n\nimpl FromBencode for IntegerWrapper {\n    const EXPECTED_RECURSION_DEPTH: usize = 0;\n\n    fn decode_bencode_object(object: Object) -\u003e Result\u003cSelf, Error\u003e {\n        // This is an example for content handling. It would also be possible\n        // to call  `i64::decode_bencode_object(object)` directly.\n        let content = object.try_into_integer()?;\n        let number = content.parse::\u003ci64\u003e()?;\n\n        Ok(IntegerWrapper(number))\n    }\n}\n\nlet encoded = b\"i21e\".to_vec();\n\nlet example = IntegerWrapper::from_bencode(\u0026encoded)?;\nassert_eq!(IntegerWrapper(21), example);\n\nlet example = i64::from_bencode(\u0026encoded)?;\nassert_eq!(21, example);\n\nOk::\u003c(), Error\u003e(())\n```\n\n**Decode a byte string**\n\nIn most cases it is possible to restore a string from its bencode\nrepresentation as a byte sequence via the `String::from_utf8` and\n`str::from_utf8`.\n\n```rust\nuse bendy::decoding::{FromBencode, Object, Error};\n\n#[derive(Debug, Eq, PartialEq)]\nstruct StringWrapper(String);\n\nimpl FromBencode for StringWrapper {\n    const EXPECTED_RECURSION_DEPTH: usize = 0;\n\n    fn decode_bencode_object(object: Object) -\u003e Result\u003cSelf, Error\u003e {\n        // This is an example for content handling. It would also be possible\n        // to call  `String::decode_bencode_object(object)` directly.\n        let content = object.try_into_bytes()?;\n        let content = String::from_utf8(content.to_vec())?;\n\n        Ok(StringWrapper(content))\n    }\n}\n\nlet encoded = b\"7:content\".to_vec();\n\nlet example = StringWrapper::from_bencode(\u0026encoded)?;\nassert_eq!(StringWrapper(\"content\".to_string()), example);\n\nlet example = String::from_bencode(\u0026encoded)?;\nassert_eq!(\"content\".to_string(), example);\n\nOk::\u003c(), Error\u003e(())\n```\n\nIf the content is a non utf8 encoded string or an actual byte sequence the\n`AsString` wrapper might be useful to restore the bencode string object as\na sequence of bytes through an object of type `Vec\u003cu8\u003e`.\n\n```rust\nuse bendy::{\n    decoding::{FromBencode, Object, Error},\n    encoding::AsString,\n};\n\n#[derive(Debug, Eq, PartialEq)]\nstruct ByteStringWrapper(Vec\u003cu8\u003e);\n\nimpl FromBencode for ByteStringWrapper {\n    const EXPECTED_RECURSION_DEPTH: usize = 0;\n\n    fn decode_bencode_object(object: Object) -\u003e Result\u003cSelf, Error\u003e {\n        let content = AsString::decode_bencode_object(object)?;\n        Ok(ByteStringWrapper(content.0))\n    }\n}\n\nlet encoded = b\"7:content\".to_vec();\n\nlet example = ByteStringWrapper::from_bencode(\u0026encoded)?;\nassert_eq!(ByteStringWrapper(b\"content\".to_vec()), example);\n\nlet example = AsString::from_bencode(\u0026encoded)?;\nassert_eq!(b\"content\".to_vec(), example.0);\n\nOk::\u003c(), Error\u003e(())\n```\n\n**Decode a dictionary**\n\nUnwrapping the bencode object into a dictionary will provide a dictionary\ndecoder which can be used to access the included key-value pairs.\n\nTo improve the error handling in case of huge or multiple nested dictionaries\nthe decoding module provides a `ResultExt` trait which allows to add a context\ndescription in case of an error. If multiple context calls are nested they will\nconcatenated in a dot notation like style.\n\n```rust\nuse bendy::decoding::{FromBencode, Object, Error, ResultExt};\n\n#[derive(Debug, Eq, PartialEq)]\nstruct Example {\n    label: String,\n    counter: u64,\n}\n\nimpl FromBencode for Example {\n    const EXPECTED_RECURSION_DEPTH: usize = 1;\n\n    fn decode_bencode_object(object: Object) -\u003e Result\u003cSelf, Error\u003e {\n        let mut counter = None;\n        let mut label = None;\n\n        let mut dict = object.try_into_dictionary()?;\n        while let Some(pair) = dict.next_pair()? {\n            match pair {\n                (b\"counter\", value) =\u003e {\n                    counter = u64::decode_bencode_object(value)\n                        .context(\"counter\")\n                        .map(Some)?;\n                },\n                (b\"label\", value) =\u003e {\n                    label = String::decode_bencode_object(value)\n                        .context(\"label\")\n                        .map(Some)?;\n                },\n                (unknown_field, _) =\u003e {\n                    return Err(Error::unexpected_field(String::from_utf8_lossy(\n                        unknown_field,\n                    )));\n                },\n            }\n        }\n\n        let counter = counter.ok_or_else(|| Error::missing_field(\"counter\"))?;\n        let label= label.ok_or_else(|| Error::missing_field(\"label\"))?;\n\n        Ok(Example { counter, label })\n    }\n}\n\nlet encoded = b\"d7:counteri0e5:label7:Examplee\".to_vec();\nlet expected = Example { label: \"Example\".to_string(), counter: 0 };\n\nlet example = Example::from_bencode(\u0026encoded)?;\nassert_eq!(expected, example);\n\nOk::\u003c(), Error\u003e(())\n```\n\n**Decode a list**\n\nUnwrapping the bencode object into a list will provide a list decoder which can\nbe used to access the contained elements.\n\n```rust\nuse bendy::decoding::{FromBencode, Object, Error};\n\n#[derive(Debug, PartialEq, Eq)]\nstruct Location(i64, i64);\n\nimpl FromBencode for Location {\n    const EXPECTED_RECURSION_DEPTH: usize = 1;\n\n    fn decode_bencode_object(object: Object) -\u003e Result\u003cSelf, Error\u003e {\n        let mut list = object.try_into_list()?;\n\n        let x = list.next_object()?.ok_or(Error::missing_field(\"x\"))?;\n        let x = i64::decode_bencode_object(x)?;\n\n        let y = list.next_object()?.ok_or(Error::missing_field(\"y\"))?;\n        let y = i64::decode_bencode_object(y)?;\n\n        Ok(Location(x, y))\n    }\n}\n\nlet encoded = b\"li2ei3ee\".to_vec();\nlet expected = Location(2, 3);\n\nlet example = Location::from_bencode(\u0026encoded)?;\nassert_eq!(expected, example);\n\nOk::\u003c(), Error\u003e(())\n```\n\n### Optional: Limitation of recursive parsing\n\n**What?**\n\nThe library allows to set an expected recursion depth limit for de- and encoding.\nIf set, the parser will use this value as an upper limit for the validation of any nested\ndata structure and abort with an error if an additional level of nesting is detected.\n\nWhile the encoding limit itself is primarily there to increase the confidence of bendy\nusers in their own validation code, the decoding limit should be used to avoid\nparsing of malformed or malicious external data.\n\n - The encoding limit can be set through the `MAX_DEPTH` constant in any implementation\n   of the `ToBencode` trait.\n - The decoding limit can be set through the `EXPECTED_RECURSION_DEPTH` constant in any\n   implementation of the `FromBencode` trait.\n\n**How?**\n\nThe nesting level calculation always starts on level zero, is incremented by one when\nthe parser enters a nested bencode element (i.e. list, dictionary) and decrement as\nsoon as the related element ends. Therefore any values decoded as bencode strings\nor integers do not affect the nesting limit.\n\n### Serde Support\n\nBendy supports serde when the `serde` feature is enabled:\n\n```toml\n[dependencies]\nbendy = { version = \"^0.3\", features = [\"std\", \"serde\"] }\nserde = { version = \"1.0\", features = [\"derive\"] }\n```\n\nWith the feature enabled, values can be serialized to and deserialized from\nbencode with `bendy::serde::from_bytes` and `bendy::serde::to_bytes`\nrespectively:\n\n\n```rust\n# #[cfg(not(feature = \"serde\"))]\n# fn main() {}\n# #[cfg(feature = \"serde\")]\n# fn main() -\u003e Result\u003c(), bendy::serde::Error\u003e {\n\nuse serde_derive::{Deserialize, Serialize};\n\n#[serde(crate = \"serde_\")]\n#[derive(Serialize, Deserialize, PartialEq, Debug)]\nstruct Foo {\n    bar: String,\n}\n\nlet value = Foo {\n    bar: \"hello\".into(),\n};\n\nlet bencode = bendy::serde::to_bytes(\u0026value)?;\nassert_eq!(bencode, b\"d3:bar5:helloe\");\n\nlet deserialized = bendy::serde::from_bytes::\u003cFoo\u003e(\u0026bencode)?;\nassert_eq!(deserialized, value);\n\nOk(())\n\n# }\n```\n\nInformation on how Rust types are represented in bencode is available in the\n[serde module documentation](https://docs.rs/bendy/*/bendy/serde/index.html).\n\n## Usage of unsafe code\nThe parser would not require any unsafe code to work but it still contains a single unsafe call\nto `str::from_utf8_unchecked`. This call is used to avoid a duplicated UTF-8 check when the\nparser converts the bytes representing an incoming integer into a `\u0026str` after its successful\nvalidation.\n\n*Disclaimer: Further unsafe code may be introduced through the dependency on the `snafu` crate.*\n\n## Contributing\n\nWe welcome everyone to ask questions, open issues or provide merge requests.\nEach merge request will be reviewed and either landed in the main tree or given\nfeedback for changes that would be required.\n\nAll code in this repository is under the [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)\nlicense.\n","funding_links":[],"categories":["Protocols","Rust"],"sub_categories":["BitTorrent"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FP3KI%2Fbendy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FP3KI%2Fbendy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FP3KI%2Fbendy/lists"}