use std::{fs::File, io::BufReader, path::Path};
use anyhow::Context as _;
pub mod backend;
pub mod common;
pub mod discovery;
pub mod endpoint_type;
pub mod engines;
pub mod entrypoint;
pub mod grpc;
pub mod http;
pub mod hub;
pub mod audit;
pub mod kv_router;
pub mod local_model;
pub mod lora;
pub mod migration;
pub mod mocker;
pub mod model_card;
pub mod model_type;
pub mod namespace;
pub mod perf;
pub mod preprocessor;
pub mod protocols;
pub mod recorder;
pub mod request_template;
pub mod tokenizers;
pub mod tokens;
pub mod types;
pub mod utils;
#[cfg(feature = "block-manager")]
pub mod block_manager;
#[cfg(feature = "cuda")]
pub mod cuda;
pub fn file_json_field<T: serde::de::DeserializeOwned>(
json_file_path: &Path,
field_name: &str,
) -> anyhow::Result<T> {
let file = File::open(json_file_path)
.with_context(|| format!("Failed to open file: {:?}", json_file_path))?;
let reader = BufReader::new(file);
let json_data: serde_json::Value = serde_json::from_reader(reader)
.with_context(|| format!("Failed to parse JSON from file: {:?}", json_file_path))?;
let map = json_data.as_object().ok_or_else(|| {
anyhow::anyhow!("JSON root is not an object in file: {:?}", json_file_path)
})?;
let field_value = map.get(field_name).ok_or_else(|| {
anyhow::anyhow!(
"Field '{}' not found in JSON file: {:?}",
field_name,
json_file_path
)
})?;
serde_json::from_value(field_value.clone()).with_context(|| {
format!(
"Failed to deserialize field '{}' (value: {:?}) to the expected type from file: {:?}",
field_name, field_value, json_file_path
)
})
}
pub fn log_json_err(filename: &str, json: &str, err: &serde_json::Error) {
const ERROR_PREFIX: &str = ">> ";
if !(err.is_syntax() || err.is_data()) {
return;
}
let line = err.line().saturating_sub(1);
let column = err.column().saturating_sub(1);
let json_lines: Vec<&str> = json.lines().collect();
if json_lines.is_empty() {
tracing::error!("JSON parsing error in {filename}: File is empty.");
return;
}
let start_index = (line - 2).max(0);
let end_index = (line + 3).min(json_lines.len());
let mut context_lines: Vec<String> = (start_index..end_index)
.map(|i| {
if i == line {
format!("{ERROR_PREFIX}{}", json_lines[i])
} else {
format!("{:06} {}", i + 1, json_lines[i])
}
})
.collect();
let col_indicator = "_".to_string().repeat(column + ERROR_PREFIX.len()) + "^";
let error_in_context_idx = line - start_index;
if error_in_context_idx < context_lines.len() {
context_lines.insert(error_in_context_idx + 1, col_indicator);
}
tracing::error!(
"JSON parsing error in {filename}: Line {}, column {}:\n{}",
err.line(),
err.column(),
context_lines.join("\n")
);
}
#[cfg(test)]
mod file_json_field_tests {
use super::file_json_field;
use serde::Deserialize;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use tempfile::tempdir;
fn create_temp_json_file(dir: &Path, file_name: &str, content: &str) -> PathBuf {
let file_path = dir.join(file_name);
let mut file = File::create(&file_path)
.unwrap_or_else(|_| panic!("Failed to create test file: {:?}", file_path));
file.write_all(content.as_bytes())
.unwrap_or_else(|_| panic!("Failed to write to test file: {:?}", file_path));
file_path
}
#[derive(Debug, PartialEq, Deserialize)]
struct MyConfig {
version: String,
enabled: bool,
count: u32,
}
#[test]
fn test_success_basic() {
let tmp_dir = tempdir().unwrap();
let file_path = create_temp_json_file(
tmp_dir.path(),
"test_basic.json",
r#"{ "name": "Rust", "age": 30, "is_active": true }"#,
);
let name: String = file_json_field(&file_path, "name").unwrap();
assert_eq!(name, "Rust");
let age: i32 = file_json_field(&file_path, "age").unwrap();
assert_eq!(age, 30);
let is_active: bool = file_json_field(&file_path, "is_active").unwrap();
assert!(is_active);
}
#[test]
fn test_success_custom_struct_field() {
let tmp_dir = tempdir().unwrap();
let file_path = create_temp_json_file(
tmp_dir.path(),
"test_struct.json",
r#"{
"config": {
"version": "1.0.0",
"enabled": true,
"count": 123
},
"other_field": "value"
}"#,
);
let config: MyConfig = file_json_field(&file_path, "config").unwrap();
assert_eq!(
config,
MyConfig {
version: "1.0.0".to_string(),
enabled: true,
count: 123,
}
);
}
#[test]
fn test_file_not_found() {
let tmp_dir = tempdir().unwrap();
let non_existent_path = tmp_dir.path().join("non_existent.json");
let result: anyhow::Result<String> = file_json_field(&non_existent_path, "field");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("Failed to open file"));
}
#[test]
fn test_invalid_json_syntax() {
let tmp_dir = tempdir().unwrap();
let file_path = create_temp_json_file(
tmp_dir.path(),
"invalid.json",
r#"{ "key": "value", "bad_syntax": }"#, );
let result: anyhow::Result<String> = file_json_field(&file_path, "key");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("Failed to parse JSON from file"));
}
#[test]
fn test_json_root_not_object_array() {
let tmp_dir = tempdir().unwrap();
let file_path = create_temp_json_file(
tmp_dir.path(),
"root_array.json",
r#"[ { "item": 1 }, { "item": 2 } ]"#, );
let result: anyhow::Result<String> = file_json_field(&file_path, "item");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("JSON root is not an object"));
}
#[test]
fn test_json_root_not_object_primitive() {
let tmp_dir = tempdir().unwrap();
let file_path = create_temp_json_file(
tmp_dir.path(),
"root_primitive.json",
r#""just_a_string""#, );
let result: anyhow::Result<String> = file_json_field(&file_path, "field");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("JSON root is not an object"));
}
#[test]
fn test_field_not_found() {
let tmp_dir = tempdir().unwrap();
let file_path = create_temp_json_file(
tmp_dir.path(),
"missing_field.json",
r#"{ "existing_field": "hello" }"#,
);
let result: anyhow::Result<String> = file_json_field(&file_path, "non_existent_field");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
err.to_string()
.contains("Field 'non_existent_field' not found")
);
}
#[test]
fn test_field_type_mismatch() {
let tmp_dir = tempdir().unwrap();
let file_path = create_temp_json_file(
tmp_dir.path(),
"type_mismatch.json",
r#"{ "count": "not_an_integer" }"#,
);
let result: anyhow::Result<u32> = file_json_field(&file_path, "count");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
err.to_string()
.contains("Failed to deserialize field 'count'")
);
}
#[test]
fn test_empty_file() {
let tmp_dir = tempdir().unwrap();
let file_path = create_temp_json_file(tmp_dir.path(), "empty.json", "");
let result: anyhow::Result<String> = file_json_field(&file_path, "field");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("Failed to parse JSON from file"));
}
}