<div align="center">
<img src="https://raw.githubusercontent.com/ankit-chaubey/layer/main/docs/images/crate-tl-types-banner.svg" alt="layer-tl-types" width="100%" />
# ๐ฆ layer-tl-types
**Auto-generated Rust types for all Telegram API Layer 224 constructors, functions and enums.**
[](https://crates.io/crates/layer-tl-types)
[](https://docs.rs/layer-tl-types)
[](#license)
[](https://www.rust-lang.org/)
[](https://core.telegram.org/schema)
*2,329 TL constructors. Every Telegram type, function and enum โ as idiomatic Rust.*
</div>
---
## ๐ฆ Installation
```toml
[dependencies]
layer-tl-types = "0.4.5"
# With MTProto low-level types too (required by layer-mtproto):
layer-tl-types = { version = "0.4.5", features = ["tl-mtproto"] }
```
---
## โจ What It Does
`layer-tl-types` is the type system for the entire layer stack. It takes Telegram's `.tl` schema file (the source of truth for every type and function in the Telegram API) and, at **build time**, generates idiomatic Rust structs, enums, and trait implementations for all of them.
The result is a fully type-safe, zero-surprise Rust representation of 2,329 Telegram API definitions, with binary TL serialization and deserialization baked in via the `Serializable` and `Deserializable` traits.
---
## ๐ Generated Structure
```rust
// Every TL constructor becomes a Rust struct
// e.g. message#9cb490e9 id:int from_id:Peer ... = Message;
pub mod types {
pub struct Message {
pub id: i32,
pub from_id: Option<enums::Peer>,
pub peer_id: enums::Peer,
pub message: String,
// ... all fields, optional ones wrapped in Option<>
}
}
// Every abstract TL type becomes a Rust enum
pub enum Message {
Message(types::Message),
Service(types::MessageService),
Empty(types::MessageEmpty),
}
}
// Every TL function becomes a struct implementing RemoteCall
// e.g. messages.sendMessage#... peer:InputPeer message:string ... = Updates
pub mod functions {
pub mod messages {
pub struct SendMessage {
pub peer: enums::InputPeer,
pub message: String,
pub random_id: i64,
// ...
}
impl RemoteCall for SendMessage {
type Return = enums::Updates;
}
}
}
```
---
## ๐ง Feature Flags
| `tl-api` | โ
| Telegram API schema (`api.tl`) โ all high-level types |
| `tl-mtproto` | โ | MTProto internal schema (`mtproto.tl`) โ low-level protocol types |
| `impl-debug` | โ
| `#[derive(Debug)]` on all generated types |
| `impl-from-type` | โ
| `From<types::T> for enums::E` conversions |
| `impl-from-enum` | โ
| `TryFrom<enums::E> for types::T` conversions |
| `deserializable-functions` | โ | `Deserializable` on function types (for server-side use) |
| `name-for-id` | โ | `name_for_id(u32) -> Option<&'static str>` CRC32 lookup |
| `impl-serde` | โ | `serde::Serialize` / `Deserialize` on all types |
---
## ๐ก Usage Examples
### Serializing a TL request
```rust
use layer_tl_types::{enums, functions, Serializable};
let req = functions::messages::SendMessage {
peer: enums::InputPeer::PeerSelf,
message: "Hello!".to_string(),
random_id: 12345,
no_webpage: false,
silent: false,
background: false,
clear_draft: false,
noforwards: false,
update_stickersets_order: false,
invert_media: false,
reply_to: None,
reply_markup: None,
entities: None,
schedule_date: None,
send_as: None,
};
// Serialize to TL wire bytes (constructor ID + fields)
let bytes = req.serialize();
```
---
### Deserializing a TL response
```rust
use layer_tl_types::{Cursor, Deserializable, enums};
let mut cur = Cursor::from_slice(&response_bytes);
let msg = enums::Message::deserialize(&mut cur)?;
match msg {
enums::Message::Message(m) => println!("text: {}", m.message),
enums::Message::Service(s) => println!("service action"),
enums::Message::Empty(_) => println!("empty"),
}
```
---
### Using `RemoteCall` for type-safe RPC
```rust
use layer_tl_types::{RemoteCall, functions::updates::GetState};
// The return type is encoded as an associated type โ no guessing, no casting
let req = GetState {};
// req: impl RemoteCall<Return = enums::updates::State>
```
The `RemoteCall` trait ties the request type to its response type at compile time, so `client.invoke(&req)` returns `Result<R::Return, _>` โ fully typed.
---
### Type conversions
```rust
use layer_tl_types::{types, enums};
// types โ enums (From, enabled by impl-from-type feature)
let peer: enums::Peer = types::PeerUser { user_id: 123 }.into();
// enums โ types (TryFrom, enabled by impl-from-enum feature)
if let Ok(user) = types::PeerUser::try_from(peer) {
println!("user_id: {}", user.user_id);
}
```
---
### Name lookup (for debugging)
```rust
// Requires the `name-for-id` feature
use layer_tl_types::name_for_id;
if let Some(name) = name_for_id(0x9cb490e9) {
println!("{name}"); // "message"
}
```
---
## ๐ Updating the TL Schema
To update to a newer Telegram API layer:
```bash
# 1. Replace the schema file
cp new-api.tl layer-tl-types/tl/api.tl
# 2. Rebuild โ code regenerates automatically
cargo build
```
The `build.rs` invokes `layer-tl-gen` at compile time, so all types stay in sync with the schema. The `cargo:rerun-if-changed` instruction means only a schema change triggers regeneration, not every build.
---
## ๐ Part of the layer stack
```
layer-client
โโโ layer-mtproto
โโโ layer-tl-types โ you are here
โโโ (build) layer-tl-gen
โโโ (build) layer-tl-parser
```
---
## ๐ License
Licensed under either of, at your option:
- **MIT License** โ see [LICENSE-MIT](../LICENSE-MIT)
- **Apache License, Version 2.0** โ see [LICENSE-APACHE](../LICENSE-APACHE)
---
## ๐ค Author
**Ankit Chaubey**
[github.com/ankit-chaubey](https://github.com/ankit-chaubey) ยท [ankitchaubey.in](https://ankitchaubey.in) ยท [ankitchaubey.dev@gmail.com](mailto:ankitchaubey.dev@gmail.com)
๐ฆ [github.com/ankit-chaubey/layer](https://github.com/ankit-chaubey/layer)