Skip to content

js0-site/xboot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

English | 中文


xboot & static_ : Async Static Initialization System

A Rust project consisting of two complementary crates for initializing global static variables asynchronously before program startup.

Table of Contents

Overview

The xboot project provides a comprehensive solution for async static initialization in Rust applications. It consists of two main components:

  • xboot: Core async initialization orchestration using linkme's distributed slice mechanism
  • static_: User-friendly declarative macro interface that builds upon xboot

This system enables modern Rust applications to initialize resources like database connections, Redis clients, and other async-dependent services as module-level static variables before the main program logic begins.

Project Structure

xboot/
├── static_/               # High-level macro interface
│   ├── src/
│   │   └── lib.rs         # init! macro implementation
│   ├── tests/
│   │   └── main.rs        # Integration tests
│   └── Cargo.toml         # Package configuration
├── xboot/                 # Core initialization engine
│   ├── src/
│   │   └── lib.rs         # linkme-based implementation
│   ├── tests/
│   │   └── main.rs        # Usage example
│   └── Cargo.toml         # Package configuration
└── README.md              # This file

Components

xboot - Core Engine

xboot is the foundational crate that enables async static initialization using linkme's distributed slice mechanism. It collects async initialization functions at compile time and executes them at runtime startup.

Key Features:

  • Zero-cost compile-time collection via linker sections
  • Cross-platform support (Linux, macOS, Windows)
  • Simple macro-based API for registration
  • Compatible with tokio runtime

static_ - User Interface

static_ provides a declarative macro interface that simplifies the usage of xboot. It handles the boilerplate of creating OnceCell instances, wrapping values, and managing initialization flow.

Key Features:

  • Declarative macro for async static initialization
  • Automatic error handling with logging
  • Thread-safe access via OnceCell wrapper
  • Seamless integration with tokio runtime

Why Separate Projects?

The separation of xboot and static_ into distinct projects is a deliberate architectural decision designed to avoid dependency conflicts with the linkme crate.

The Problem: linkme Dependency Conflicts

The linkme crate, which xboot uses for distributed slice functionality, has specific requirements about how it's linked:

  1. Single Instance Required: linkme requires that only one version of the crate be linked in the final binary
  2. Compilation Conflicts: If multiple crates in the dependency graph depend on different versions of linkme, linking conflicts occur
  3. Binary Size Impact: Multiple linkme instances can increase binary size and cause symbol conflicts

The Solution: Clean Separation

By separating the project into two crates:

  • xboot: Contains the core linkme-based implementation
  • static_: Provides a clean interface that depends on xboot

Other projects can depend on static_ (or directly on xboot) as remote dependencies from crates.io, ensuring that only one version of linkme is included in the final binary.

This architecture:

  • Prevents linkme version conflicts across the dependency graph
  • Ensures consistent behavior across all dependent projects
  • Maintains a clean separation of concerns between core functionality and user interface
  • Allows independent versioning of the interface layer (static_) and core implementation (xboot)

Installation

Add to your Cargo.toml:

[dependencies]
static_ = "0.1"  # Recommended: Use the high-level interface
# Or
xboot = "0.1"    # Direct access to core functionality

Usage

use aok::Result;
use tokio::time::{Duration, sleep};
use log::info;

// Define a resource that needs async initialization
pub struct Database {
  connection: String,
}

impl Database {
  pub async fn connect(url: &str) -> Result<Self> {
    info!("Connecting to database...");
    sleep(Duration::from_secs(2)).await;
    Ok(Self { connection: url.to_string() })
  }

  pub async fn query(&self, sql: &str) -> Result<()> {
    info!("Executing query on {}: {}", self.connection, sql);
    Ok(())
  }
}

// Declare async-initialized static variable using static_
static_::init!(DB: Database async {
  Database::connect("postgres://localhost/myapp").await
});

#[tokio::main]
async fn main() -> Result<()> {
  // Initialize all registered statics
  xboot::init().await?;
  info!("All statics initialized");
  
  // Use the initialized static like a regular variable
  DB.query("SELECT * FROM users").await?;
  Ok(())
}

Design

Initialization Flow

graph TD
    A["Program Start"] --> B["static_::init! macro expands"]
    B --> C["Creates OnceCell and registers with xboot"]
    C --> D["xboot::add! macro registers function"]
    D --> E["Linker collects all functions into ASYNC slice"]
    E --> F["Runtime: xboot::init() called"]
    F --> G["Iterates through ASYNC slice"]
    G --> H["Executes all async initializations"]
    H --> I["Results stored in OnceCell instances"]
    I --> J["Static variables ready for use"]
Loading

Component Interaction

  1. static_::init!: Creates OnceCell instances and registers initialization with xboot
  2. xboot::add!: Registers async initialization functions to the distributed slice
  3. linkme: Collects all registered functions at link time
  4. xboot::init(): Executes all registered initializations at runtime

Tech Stack

Crate Purpose
linkme Distributed slice for compile-time collection
tokio Async runtime and task spawning
async_wrap OnceCell and Wrap types
paste Macro identifier concatenation
gensym Unique symbol generation
aok Result type utilities
log Error logging

License

MulanPSL-2.0


About

This project is an open-source component of js0.site ⋅ Refactoring the Internet Plan.

We are redefining the development paradigm of the Internet in a componentized way. Welcome to follow us:


xboot & static_ : 异步静态变量初始化系统

一个由两个互补的 Rust crate 组成的项目,用于在程序启动前异步初始化全局静态变量。

目录

项目概述

xboot 项目为 Rust 应用程序中的异步静态初始化提供了全面的解决方案。它由两个主要组件组成:

  • xboot: 基于 linkme 分布式切片机制的核心异步初始化编排器
  • static_: 基于 xboot 构建的声明式宏用户界面

该系统使现代 Rust 应用程序能够在主程序逻辑开始前,将数据库连接、Redis 客户端和其他依赖异步的服务初始化为模块级静态变量。

项目结构

xboot/
├── static_/               # 高级宏接口
│   ├── src/
│   │   └── lib.rs         # init! 宏实现
│   ├── tests/
│   │   └── main.rs        # 集成测试
│   └── Cargo.toml         # 包配置
├── xboot/                 # 核心初始化引擎
│   ├── src/
│   │   └── lib.rs         # 基于 linkme 的实现
│   ├── tests/
│   │   └── main.rs        # 使用示例
│   └── Cargo.toml         # 包配置
└── README.md              # 本文件

组件说明

xboot - 核心引擎

xboot 是基础 crate,使用 linkme 的分布式切片机制实现异步静态初始化。它在编译期收集异步初始化函数,在运行时启动阶段执行。

主要特性:

  • 通过链接器段实现零开销编译期收集
  • 跨平台支持(Linux、macOS、Windows)
  • 简洁的宏注册 API
  • 兼容 tokio 运行时

static_ - 用户界面

static_ 提供声明式宏接口,简化了 xboot 的使用。它处理创建 OnceCell 实例、包装值和管理初始化流程的样板代码。

主要特性:

  • 声明式宏实现异步静态初始化
  • 自动错误处理与日志记录
  • 基于 OnceCell 的线程安全访问
  • 无缝集成 tokio 运行时

为什么分离为独立项目

将 xboot 和 static_ 分离为独立项目是经过深思熟虑的架构决策,旨在避免与 linkme crate 的依赖冲突。

问题:linkme 依赖冲突

linkme crate(xboot 用于分布式切片功能)对其链接方式有特定要求:

  1. 单一实例要求: linkme 要求最终二进制文件中只链接一个版本的 crate
  2. 编译冲突: 如果依赖图中的多个 crate 依赖不同版本的 linkme,会发生链接冲突
  3. 二进制大小影响: 多个 linkme 实例会增加二进制大小并可能导致符号冲突

解决方案:清晰分离

通过将项目分离为两个 crate:

  • xboot: 包含基于 linkme 的核心实现
  • static_: 提供依赖 xboot 的简洁接口

其他项目可以从 crates.io 作为远程依赖使用 static_(或直接使用 xboot),确保最终二进制文件中只包含一个版本的 linkme

这种架构:

  • 防止整个依赖图中的 linkme 版本冲突
  • 确保所有依赖项目的行为一致性
  • 维护核心功能与用户界面之间的清晰关注点分离
  • 允许接口层(static_)和核心实现(xboot)独立版本控制

安装

Cargo.toml 中添加:

[dependencies]
static_ = "0.1"  # 推荐:使用高级接口
#
xboot = "0.1"    # 直接访问核心功能

使用

use aok::Result;
use tokio::time::{Duration, sleep};
use log::info;

// 定义需要异步初始化的资源
pub struct Database {
  connection: String,
}

impl Database {
  pub async fn connect(url: &str) -> Result<Self> {
    info!("正在连接数据库...");
    sleep(Duration::from_secs(2)).await;
    Ok(Self { connection: url.to_string() })
  }

  pub async fn query(&self, sql: &str) -> Result<()> {
    info!("在 {} 上执行查询: {}", self.connection, sql);
    Ok(())
  }
}

// 使用 static_ 声明异步初始化的静态变量
static_::init!(DB: Database async {
  Database::connect("postgres://localhost/myapp").await
});

#[tokio::main]
async fn main() -> Result<()> {
  // 初始化所有注册的静态变量
  xboot::init().await?;
  info!("所有静态变量初始化完成");
  
  // 像普通变量一样使用已初始化的静态变量
  DB.query("SELECT * FROM users").await?;
  Ok(())
}

设计

初始化流程

graph TD
    A["程序启动"] --> B["static_::init! 宏展开"]
    B --> C["创建 OnceCell 并向 xboot 注册"]
    C --> D["xboot::add! 宏注册函数"]
    D --> E["链接器将所有函数收集到 ASYNC 切片"]
    E --> F["运行时: 调用 xboot::init()"]
    F --> G["遍历 ASYNC 切片"]
    G --> H["执行所有异步初始化"]
    H --> I["结果存储在 OnceCell 实例中"]
    I --> J["静态变量准备就绪"]
Loading

组件交互

  1. static_::init!: 创建 OnceCell 实例并向 xboot 注册初始化
  2. xboot::add!: 将异步初始化函数注册到分布式切片
  3. linkme: 在链接期收集所有注册的函数
  4. xboot::init(): 在运行时执行所有注册的初始化

技术栈

Crate 用途
linkme 分布式切片,编译期收集
tokio 异步运行时和任务 spawn
async_wrap OnceCellWrap 类型
paste 宏标识符拼接
gensym 唯一符号生成
aok Result 类型工具
log 错误日志

许可证

MulanPSL-2.0


关于

本项目为 js0.site ⋅ 重构互联网计划 的开源组件。

我们正在以组件化的方式重新定义互联网的开发范式,欢迎关注:

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published