Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Upgrading the TL Layer

Note

This project is no longer maintained or supported. Its original purpose for personal SDK/APK experimentation and learning has been fulfilled.

Instead, please use ferogram, which will receive future development and updates. Development may proceed at a slower pace.

The Telegram API evolves continuously. Each new layer adds constructors, modifies existing types, and deprecates old ones. Upgrading layer is designed to be a one-file operation.

How the system works

layer-tl-types is fully auto-generated at build time:

tl/api.tl          (source of truth: the only file you replace)
    │
    ▼
build.rs           (reads api.tl, invokes layer-tl-gen)
    │
    ▼
$OUT_DIR/
  generated_common.rs     ← pub const LAYER: i32 = 224;
  generated_types.rs      ← pub mod types { ... }
  generated_enums.rs      ← pub mod enums { ... }
  generated_functions.rs  ← pub mod functions { ... }

The LAYER constant is extracted from the // LAYER N comment on the first line of api.tl. Everything else flows from there.

Step 1: Replace api.tl

# Get the new schema from Telegram's official sources
# (TDLib repository, core.telegram.org, or unofficial mirrors)

cp new-layer-224.tl layer-tl-types/tl/api.tl

Make sure the first line of the file is:

// LAYER 224

Step 2: Build

cargo build 2>&1 | head -40

The build script automatically:

  • Parses the new schema
  • Generates updated Rust source
  • Patches pub const LAYER: i32 = 224; into generated_common.rs

If there are no breaking type changes in layer-client, it compiles cleanly.

Step 3: Fix compile errors

New layers commonly add fields to existing structs. These show up as errors like:

error[E0063]: missing field `my_new_field` in initializer of `types::SomeStruct`

Fix them by adding the field with a sensible default:

#![allow(unused)]
fn main() {
// Boolean flags → false
my_new_flag: false,

// Option<T> fields → None
my_new_option: None,

// i32/i64 counts → 0
my_new_count: 0,

// String fields → String::new()
my_new_string: String::new(),
}

New enum variants in match statements:

#![allow(unused)]
fn main() {
// error[E0004]: non-exhaustive patterns: `Update::NewVariant(_)` not covered
Update::NewVariant(_) => { /* handle or ignore */ }
// OR add to the catch-all:
_ => {}
}

Step 4: Bump version and publish

# In Cargo.toml workspace section
version = "0.5.0"

Then publish in dependency order (see Publishing).

What propagates automatically

Once api.tl is updated with the new layer number, these update with zero additional changes:

WhatWhereHow
tl::LAYER constantlayer-tl-types/src/lib.rsbuild.rs patches it
invokeWithLayer calllayer-client/src/lib.rs:1847reads tl::LAYER
/about bot commandlayer-bot/src/main.rs:333reads tl::LAYER at runtime
Badge in READMEManual: update onceString replace

Diff the changes

diff old-api.tl layer-tl-types/tl/api.tl | grep "^[<>]" | head -40

This shows you exactly which constructors changed, helping you anticipate which layer-client files need updating.