Skip to content

AzzoDude/js-protocol

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

js-protocol

Crates.io Documentation License: MIT

A high-performance, zero-allocation, fully compile-safe Rust representation of the Chrome DevTools JavaScript Protocol (js_protocol), generated directly from the official protocol definitions.


🚀 Key Design Goals & Features

Most auto-generated CDP crates output raw, unidiomatic APIs with substantial runtime allocation overhead. This library is designed from the ground up to solve these issues:

1. Idiomatic Rust Naming Conventions

  • All generated struct fields, getters, and builder setter methods are translated from the protocol's raw camelCase to standard Rust snake_case (e.g., executionContextId becomes execution_context_id, and objectGroup becomes object_group).
  • Standard #[serde(rename = "...")] attributes ensure the serialized JSON wire protocol matches the exact formats required by Chrome.

2. Zero-Copy String Management

  • Utilizes Cow<'a, str> instead of allocating heap memory (String) for string properties.
  • String arguments in builders use impl Into<Cow<'a, str>>, allowing you to pass static string literals (&str) or owned strings without unnecessary heap allocations.

3. Compile-Time Argument Safety

  • The builder pattern differentiates between required and optional parameters. Required parameters are passed directly as arguments to the builder(...) function, guaranteeing protocol compliance at compile time:
    // `expression` is required (passed to builder), `silent` is optional (chained)
    let params = EvaluateParams::builder("1 + 1")
        .silent(true)
        .build();

4. Zero Dependencies & No Async Runtime Lock-in

  • Contains zero bloated dependencies (depends only on serde and serde_json).
  • Does not include a WebSocket client or force a specific async runtime (like tokio). This keeps the package extremely lightweight, compile-fast, and compatible with any async runtime or network stack.

📦 Installation

Add this to your Cargo.toml:

[dependencies]
js-protocol = { version = "0.1.3", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

🛠 Usage Examples

1. Constructing a Request with Optional Parameters

use js_protocol::runtime::EvaluateParams;

fn main() {
    // 1. Build the command parameters
    let params = EvaluateParams::builder("console.log('Hello from Rust!')")
        .silent(true)
        .build();
    
    // 2. Read-only getters
    println!("Expression to run: {}", params.expression());
    
    // 3. Serialize to wire protocol payload (skips unset Option fields)
    let payload = serde_json::to_string(&params).unwrap();
    println!("Payload: {}", payload);
    // Output: {"expression":"console.log('Hello from Rust!')","silent":true}
}

2. Handling Command Request/Response Types

Every parameter struct implements crate::CdpCommand<'a> which binds it to its command method and its corresponding response (Returns) type:

use js_protocol::runtime::{EvaluateParams, EvaluateReturns};
use js_protocol::CdpCommand;

fn evaluate_js() {
    let params = EvaluateParams::builder("1 + 2").build();

    // The trait binds this command to its method name and response type:
    assert_eq!(EvaluateParams::METHOD, "Runtime.evaluate");
    
    // In your network client:
    // let response_json = websocket.send_command(EvaluateParams::METHOD, &params).await;
    // let response: EvaluateReturns = serde_json::from_str(&response_json).unwrap();
}

🏗 Code Generation Mechanics

The code is dynamically compiled using a custom Python script that performs advanced schema analysis:

  1. Fixed-Point Lifetime Propagation Pass: The generator performs iterative analysis over the CDP types to detect circular type references, nesting, and dependency hierarchies. It automatically determines which types must have a lifetime parameter (<'a>) and wraps recursive structures inside Box to prevent infinite-size compilation errors.
  2. HTML/Markdown Escaping: Schema documentation from the Chrome DevTools Protocol contains raw markdown and HTML brackets. The generator cleans and escapes these brackets into valid Rustdoc format, keeping compilation entirely warning-free.
  3. Domain-Specific Feature Flags: Every CDP domain is represented by a Rust feature flag. You can optimize compile times by only compiling the domains your project needs:
    # Compile only the runtime and debugger domains
    js-protocol = { version = "0.1.3", default-features = false, features = ["runtime", "debugger"] }

Regenerating the Code

To regenerate the Rust modules from a local protocol file:

python scripts/generate_rust_code.py --name js-protocol

⚖ License

Distributed under the MIT License. See LICENSE for more information.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors