{"id":22072575,"url":"https://github.com/broxus/tl-proto","last_synced_at":"2025-07-24T11:30:40.316Z","repository":{"id":57669945,"uuid":"440952806","full_name":"broxus/tl-proto","owner":"broxus","description":"A collection of traits for working with TL","archived":false,"fork":false,"pushed_at":"2025-03-25T17:40:55.000Z","size":166,"stargazers_count":5,"open_issues_count":0,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-23T02:48:54.799Z","etag":null,"topics":["everscale","tl"],"latest_commit_sha":null,"homepage":"https://docs.rs/tl-proto","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/broxus.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}},"created_at":"2021-12-22T18:40:50.000Z","updated_at":"2025-03-25T17:40:59.000Z","dependencies_parsed_at":"2024-07-19T00:46:34.116Z","dependency_job_id":null,"html_url":"https://github.com/broxus/tl-proto","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/broxus/tl-proto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/broxus%2Ftl-proto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/broxus%2Ftl-proto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/broxus%2Ftl-proto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/broxus%2Ftl-proto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/broxus","download_url":"https://codeload.github.com/broxus/tl-proto/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/broxus%2Ftl-proto/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266620870,"owners_count":23957497,"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-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"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":["everscale","tl"],"created_at":"2024-11-30T21:13:47.507Z","updated_at":"2025-07-24T11:30:39.998Z","avatar_url":"https://github.com/broxus.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"## tl-proto \u0026emsp; [![Latest Version]][crates.io] [![tl-proto: rustc 1.56+]][Rust 1.56] [![Workflow badge]][Workflow] [![License MIT badge]][License MIT]\n\n[Latest Version]: https://img.shields.io/crates/v/tl-proto.svg\n\n[crates.io]: https://crates.io/crates/tl-proto\n\n[tl-proto: rustc 1.56+]: https://img.shields.io/badge/rustc-1.56+-lightgray.svg\n\n[Rust 1.56]: https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html\n\n[Workflow badge]: https://img.shields.io/github/actions/workflow/status/broxus/tl-proto/master.yml?branch=master\n\n[Workflow]: https://github.com/broxus/tl-proto/actions?query=workflow%3Amaster\n\n[License MIT badge]: https://img.shields.io/badge/license-MIT-blue.svg\n\n[License MIT]: https://opensource.org/licenses/MIT\n\nA collection of traits for working with [TL](https://core.telegram.org/mtproto/TL) serialization/deserialization.\n\n### Example\n\n```text\n/* my_proto.tl */\n\nint ? = Int;\nlong ? = Long;\nstring ? = String;\nbytes data:string = Bytes;\n\nint256 8*[ int ] = Int256;\n\npub.ed25519 key:int256 = PublicKey;\npub.aes key:int256 = PublicKey;\npub.overlay name:bytes = PublicKey;\n\nadnl.address.udp ip:int port:int = adnl.Address;\n\ntonNode.blockId workchain:int shard:long seqno:int = tonNode.BlockId;\n\n--- functions ---\n\nliteServer.lookupBlock mode:# id:tonNode.blockId lt:mode.1?long utime:mode.2?int = liteServer.BlockHeader;\n```\n\n\u003e NOTE: TL scheme is parsed by [`tl-scheme`](./scheme) crate at compile time.\n\u003e It doesn't cover full TL grammer, but it's enough for most of the cases.\n\n```rust,ignore\nuse tl_proto::{TlRead, TlWrite};\n\n/// You can declare \"bare\" structs, which\n/// doesn't have an associated TL id.\n///\n/// NOTE: enums can only be used as bare\n/// with TlWrite, because there is no way to\n/// know the exact variant without an id to\n/// implement TlRead.\n#[derive(TlRead, TlWrite)]\n#[tl(size_hint = 32)]\nstruct HashRef\u003c'tl\u003e(\u0026'tl [u8; 32]);\n\n/// Or you can declare \"boxed\" structs, which\n/// have one or more associated TL ids.\n///\n/// NOTE: in case of boxed enum with provided scheme,\n/// all variants must have the same constructor kind\n/// (all functions or all types). And if all variants\n/// are types, they must refer to the same boxed type.\n#[derive(TlRead, TlWrite)]\n#[tl(boxed, scheme = \"my_proto.tl\")]\nenum PublicKey\u003c'tl\u003e {\n    /// `id` attribute is required for boxed enums.\n    /// It can be either a raw id or a name of a variant\n    /// from the scheme (in later case, `scheme` or `scheme_inline`\n    /// container attribute is required).\n    #[tl(id = \"pub.aes\")]\n    Aes { key: HashRef\u003c'tl\u003e },\n\n    /// `size_hint` is used to optimize `TlWrite::max_size_hint`\n    /// implementation. If this attribute is specified, it\n    /// will be used as is instead of computing the size of fields.\n    #[tl(id = \"pub.ed25519\", size_hint = 32)]\n    Ed25519 { key: HashRef\u003c'tl\u003e },\n\n    /// Note that lifetime is called `'tl`, it is a special\n    /// name which refers to the lifetime of the buffer\n    /// from which this struct was deserialized.\n    #[tl(id = \"pub.overlay\")]\n    Overlay { name: \u0026'tl [u8] },\n}\n\n#[derive(TlRead, TlWrite)]\n#[tl(boxed)]\nenum Address\u003c'tl\u003e {\n    /// You can also specify raw id of a variant\n    #[tl(id = 0x670da6e7)]\n    Udp { ip: i32, port: i32 },\n\n    #[tl(id = 0xe31d63fa)]\n    Udp6 { ip: \u0026'tl [u8; 16], port: i32 },\n\n    #[tl(id = 0x092b02eb)]\n    Tunnel {\n        to: HashRef\u003c'tl\u003e,\n        pubkey: PublicKey\u003c'tl\u003e,\n    },\n}\n\n#[derive(TlRead, TlWrite)]\nstruct BlockId {\n    workchain: i32,\n    /// If you need custom deserialization logic for the field,\n    /// you can specify either `with` attribute or separate\n    /// `write_with`/`read_with` attributes.\n    ///\n    /// `with` must point to a module which must contain the\n    /// following public functions:\n    /// For `TlWrite`:\n    ///   - `fn size_hint(v: \u0026T) -\u003e usize;`\n    ///   - `fn write\u003cP: TlPacket\u003e(v: \u0026T, p: \u0026mut P);`\n    /// For `TlRead`:\n    ///   - `fn read(packet: \u0026[u8], offset: \u0026mut usize) -\u003e TlResult\u003cT\u003e;`\n    ///\n    /// `write_with` must point to a function with the following signature:\n    /// `fn write\u003cP: TlPacket\u003e(v: \u0026T, p: \u0026mut P);`\n    /// NOTE: `write_with` requires `size_hint` attribute.\n    ///\n    /// `read_with` must point to a function with the following signature:\n    /// `fn read(packet: \u0026[u8], offset: \u0026mut usize) -\u003e TlResult\u003cT\u003e;`\n    #[tl(with = \"tl_shard\")]\n    shard: u64,\n    seqno: u32,\n}\n\n/// `with` is similar to the same attribute in serde\nmod tl_shard {\n    use tl_proto::{TlPacket, TlRead, TlWrite};\n\n    pub const fn size_hint(_: \u0026u64) -\u003e usize { 8 }\n\n    pub fn write\u003cP: TlPacket\u003e(shard: \u0026u64, packet: \u0026mut P) {\n        shard.write_to(packet);\n    }\n\n    pub fn read(packet: \u0026mut \u0026[u8]) -\u003e tl_proto::TlResult\u003cu64\u003e {\n        let shard = u64::read_from(packet)?;\n        if shard % 10000 == 0 {\n            Ok(shard)\n        } else {\n            Err(tl_proto::TlError::InvalidData)\n        }\n    }\n}\n\n/// You can also declare \"bare\" structs and specify\n/// the type id of their boxed variant, so something\n/// like `tl_proto::BoxedWrapper` can be used later.\n///\n/// See also:\n/// - `tl_proto::deserialize_as_boxed` - read bare type as boxed\n/// - `tl_proto::serialize_as_boxed` - write bare type as boxed\n/// - `tl_proto::hash_as_boxed` - compute hash of the boxed repr\nimpl tl_proto::BoxedConstructor for BlockId {\n    /// There is a way to compute id of a variant at\n    /// compile time using the provided scheme\n    const TL_ID: u32 = tl_proto::id!(\"liteServer.lookupBlock\", scheme = \"my_proto.tl\");\n}\n\n/// There s a way to have a struct with optional fields\n#[derive(TlRead, TlWrite)]\n#[tl(boxed, id = \"liteServer.lookupBlock\", scheme = \"my_proto.tl\")]\nstruct LookupBlock {\n    /// At first, there must be a field, marked with `flags` attribute.\n    ///\n    /// NOTE: It must precede the fields that depend on it.\n    #[tl(flags)]\n    mode: (),\n    id: BlockId,\n    /// Fields with `flags_bit` attribute must be `Option`s\n    #[tl(flags_bit = 1)]\n    lt: Option\u003cu64\u003e,\n    /// You can also explicitly specify the flags field\n    /// (e.g. when multiple fields with `flags` attribute are used)\n    #[tl(flags_field = \"mode\", flags_bit = 2)]\n    utime: Option\u003cu32\u003e,\n\n    // Or you can use the shorter syntax:\n    //\n    // #[tl(flags_bit = \"mode.2\")]\n    // utime: Option\u003cu32\u003e,\n}\n\n#[derive(TlWrite)]\nstruct StructWithSignature {\n    value: u64,\n    /// `signature` is used by `TlWrite` to simplify signature\n    /// verification. In most cases you sign a data with an empty signature,\n    /// so this attribute just writes `\u0026[]` to the packet of type `P` if\n    /// `\u003cP as TlPacket\u003e::TARGET == TlTarget::Hasher`\n    #[tl(signature)]\n    my_signature: [u8; 64],\n}\n\n/// You can constraint the type by its representation\n/// (`tl_proto::Bare` / `tl_proto::Boxed`)\nfn ultra_hash\u003cT: TlWrite\u003cRepr = tl_proto::Boxed\u003e\u003e(object: T) -\u003e u32 {\n    tl_proto::serialize(object).len() as u32\n}\n\nfn main() {\n    // When the struct or enum has `TlRead` derive macro\n    // and it is marked `boxed`, it also exposes\n    // either `TL_ID` constant (in case of struct)\n    // or `TL_ID_*` constants (in case of enum) where\n    // `*` is a variant name in screaming snake case\n    assert_eq!(PublicKey::TL_ID_AES, 0x2dbcadd4);\n\n    let bytes = tl_proto::serialize(\u0026Address::Udp {\n        ip: 123,\n        port: 3000,\n    });\n\n    let decoded = tl_proto::deserialize::\u003cAddress\u003e(\u0026bytes).unwrap();\n    assert!(matches!(\n        decoded,\n        Address::Udp {\n            ip: 123,\n            port: 3000,\n        }\n    ));\n}\n```\n\n### Specification\n\n| Type | Pseudocode |\n| -------- | -------- |\n| `()` | `[]` |\n| `i32`,`u32`,`i64`,`u64` | `little_endian(x)` |\n| `true` | `[0xb5, 0x75, 0x72, 0x99]` |\n| `false` | `[0x37, 0x97, 0x79, 0xbc]`\n| `[u8; N], N % 4 ≡ 0`) | `[…x]` |\n| `Vec\u003cu8\u003e, len \u003c 254`) | \u003ccode\u003e[len as u8, …x, …padding_to_4(len)]\u003c/code\u003e |\n| `Vec\u003cu8\u003e, len ≥ 254`) | \u003ccode\u003e[254, …little_endian(x)[0..=2], …x, …padding_to_4(len)]\u003c/code\u003e |\n| `Vec\u003cT\u003e` | `[…little_endian(len as u32), …map(…x, repr)]` |\n| `(T0, … , Tn)` | `[…repr(T0), … , …repr(Tn)]`  |\n| `Option\u003cT\u003e` | `{ Some(x) ⇒ repr(x), None ⇒ [] }` |\n| `enum { T0, …, Tn }` | `{ T0(x) ⇒ […id(T0), …repr(x)], …, Tn(x) ⇒ […id(Tn), …repr(x)] }` |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbroxus%2Ftl-proto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbroxus%2Ftl-proto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbroxus%2Ftl-proto/lists"}