ngdp-bpsv

Crates.iongdp-bpsv
lib.rsngdp-bpsv
version0.4.3
created_at2025-06-28 14:44:14.966019+00
updated_at2025-08-11 12:06:07.366818+00
descriptionBPSV (Blizzard Pipe-Separated Values) parser and writer for NGDP
homepagehttps://github.com/wowemulation-dev/cascette-rs
repositoryhttps://github.com/wowemulation-dev/cascette-rs
max_upload_size
id1729894
size179,785
Daniel S. Reichenbach (danielsreichenbach)

documentation

README

ngdp-bpsv

A Rust parser and writer for BPSV (Blizzard Pipe-Separated Values) format, used throughout Blizzard's NGDP (Next Generation Distribution Pipeline) system.

Overview

BPSV is a structured data format used by Blizzard Entertainment across their content delivery network. It features:

  • 📊 Typed columns (STRING, HEX, DEC)
  • 🔢 Sequence numbers for version tracking
  • 📋 Pipe-separated values with header definitions
  • ✅ Built-in validation for data types and constraints

Installation

Add this to your Cargo.toml:

[dependencies]
ngdp-bpsv = "0.3"

Quick Start

Parsing BPSV Data

use ngdp_bpsv::BpsvDocument;

let data = r#"Region!STRING:0|BuildId!DEC:4|Hash!HEX:32
## seqn = 12345
us|1234|deadbeefcafebabedeadbeefcafebabe
eu|5678|1234567890abcdef1234567890abcdef"#;

let doc = BpsvDocument::parse(data)?;
println!("Sequence: {:?}", doc.sequence_number());
println!("Rows: {}", doc.rows().len());

Building BPSV Data

use ngdp_bpsv::{BpsvBuilder, BpsvFieldType, BpsvValue};

let mut builder = BpsvBuilder::new();
builder.add_field("Region", BpsvFieldType::String(0))?;
builder.add_field("BuildId", BpsvFieldType::Decimal(4))?;
builder.set_sequence_number(12345);

builder.add_row(vec![
    BpsvValue::String("us".to_string()),
    BpsvValue::Decimal(1234),
])?;

let output = builder.build()?;

Format Specification

Field Types

  • STRING:length - String field (length 0 = unlimited)
  • HEX:length - Hexadecimal field (length in bytes, N bytes = N*2 hex chars)
  • DEC:length - Decimal integer field

Structure

FieldName!TYPE:length|AnotherField!TYPE:length
## seqn = 12345
value1|value2
value3|value4

Examples

Parse Ribbit Version Data

use ngdp_bpsv::BpsvDocument;

let versions_data = std::fs::read_to_string("versions.bpsv")?;
let doc = BpsvDocument::parse(&versions_data)?;

// Find all US region entries
let us_rows = doc.find_rows_by_field("Region", "us")?;
for row_idx in us_rows {
    let row = &doc.rows()[row_idx];
    if let Some(build_id) = row.get_raw_by_name("BuildId", doc.schema()) {
        println!("US Build: {}", build_id);
    }
}

Type-Safe Value Access

// Access typed values from a row
let row = &doc.rows()[0];
let schema = doc.schema();

// Get raw string value
let region = row.get_raw_by_name("Region", schema).unwrap();

// Get typed value (requires mutable row)
let mut row = doc.rows()[0].clone();
let typed_values = row.get_typed_values(schema)?;
if let BpsvValue::Decimal(build_id) = &typed_values[1] {
    println!("Build ID: {}", build_id);
}

Build CDN Configuration

use ngdp_bpsv::{BpsvBuilder, BpsvFieldType, BpsvValue};

let mut builder = BpsvBuilder::new();
builder.add_field("Name", BpsvFieldType::String(0))?;
builder.add_field("Path", BpsvFieldType::String(0))?;
builder.add_field("Hosts", BpsvFieldType::String(0))?;
builder.set_sequence_number(2241282);

builder.add_row(vec![
    BpsvValue::String("us".to_string()),
    BpsvValue::String("tpr/wow".to_string()),
    BpsvValue::String("us.cdn.blizzard.com level3.blizzard.com".to_string()),
])?;

println!("{}", builder.build()?);

Features

  • 🚀 Fast parsing with minimal allocations
  • 🔍 Type validation and error reporting
  • 🏗️ Builder pattern for document creation
  • 📝 Round-trip compatibility (parse → build → parse)
  • 🔧 Case-insensitive field type parsing
  • 📭 Empty value support for all field types

Error Handling

The library provides detailed error types for common issues:

use ngdp_bpsv::{BpsvDocument, Error};

match BpsvDocument::parse(data) {
    Ok(doc) => println!("Parsed {} rows", doc.rows().len()),
    Err(Error::InvalidHeader { line }) => {
        println!("Invalid header: {}", line);
    }
    Err(Error::RowValidation { row_index, reason }) => {
        println!("Row {} invalid: {}", row_index, reason);
    }
    Err(e) => println!("Parse error: {}", e),
}

Performance

The parser is optimized for the typical BPSV use cases:

  • Small to medium documents (< 10,000 rows)
  • Fast field lookups via schema indexing
  • Lazy type parsing (on-demand conversion)

See the benchmarks for detailed performance metrics.

📄 License

This project is dual-licensed under either:

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

🫶 Acknowledgments

This crate is part of the cascette-rs project, providing tools for World of Warcraft emulation development.

Commit count: 0

cargo fmt