use serde::{Deserialize, Serialize};
pub trait FromSdkSpec: Sized {
fn from_sdk(spec: crate::BenchSpec) -> Self;
fn to_sdk(&self) -> crate::BenchSpec;
}
pub trait FromSdkSample: Sized {
fn from_sdk(sample: crate::BenchSample) -> Self;
fn to_sdk(&self) -> crate::BenchSample;
}
pub trait FromSdkReport<Spec: FromSdkSpec, Sample: FromSdkSample>: Sized {
fn from_sdk_report(report: crate::RunnerReport) -> Self;
}
pub trait FromSdkError: Sized {
fn from_sdk(err: crate::types::BenchError) -> Self;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BenchSpecTemplate {
pub name: String,
pub iterations: u32,
pub warmup: u32,
}
impl From<crate::BenchSpec> for BenchSpecTemplate {
fn from(spec: crate::BenchSpec) -> Self {
Self {
name: spec.name,
iterations: spec.iterations,
warmup: spec.warmup,
}
}
}
impl From<BenchSpecTemplate> for crate::BenchSpec {
fn from(spec: BenchSpecTemplate) -> Self {
Self {
name: spec.name,
iterations: spec.iterations,
warmup: spec.warmup,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BenchSampleTemplate {
pub duration_ns: u64,
pub cpu_time_ms: Option<u64>,
pub peak_memory_kb: Option<u64>,
pub process_peak_memory_kb: Option<u64>,
}
impl From<crate::BenchSample> for BenchSampleTemplate {
fn from(sample: crate::BenchSample) -> Self {
Self {
duration_ns: sample.duration_ns,
cpu_time_ms: sample.cpu_time_ms,
peak_memory_kb: sample.peak_memory_kb,
process_peak_memory_kb: sample.process_peak_memory_kb,
}
}
}
impl From<BenchSampleTemplate> for crate::BenchSample {
fn from(sample: BenchSampleTemplate) -> Self {
Self {
duration_ns: sample.duration_ns,
cpu_time_ms: sample.cpu_time_ms,
peak_memory_kb: sample.peak_memory_kb,
process_peak_memory_kb: sample.process_peak_memory_kb,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BenchReportTemplate {
pub spec: BenchSpecTemplate,
pub samples: Vec<BenchSampleTemplate>,
pub phases: Vec<crate::SemanticPhase>,
pub timeline: Vec<crate::HarnessTimelineSpan>,
}
impl From<crate::RunnerReport> for BenchReportTemplate {
fn from(report: crate::RunnerReport) -> Self {
Self {
spec: report.spec.into(),
samples: report.samples.into_iter().map(Into::into).collect(),
phases: report.phases,
timeline: report.timeline,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum BenchErrorVariant {
InvalidIterations,
UnknownFunction { name: String },
ExecutionFailed { reason: String },
ConfigError { message: String },
IoError { message: String },
}
impl From<crate::types::BenchError> for BenchErrorVariant {
fn from(err: crate::types::BenchError) -> Self {
match err {
crate::types::BenchError::Runner(runner_err) => match runner_err {
crate::timing::TimingError::NoIterations { .. } => {
BenchErrorVariant::InvalidIterations
}
crate::timing::TimingError::Execution(msg) => {
BenchErrorVariant::ExecutionFailed { reason: msg }
}
},
crate::types::BenchError::UnknownFunction(name, _available) => {
BenchErrorVariant::UnknownFunction { name }
}
crate::types::BenchError::Execution(msg) => {
BenchErrorVariant::ExecutionFailed { reason: msg }
}
crate::types::BenchError::Io(e) => BenchErrorVariant::IoError {
message: e.to_string(),
},
crate::types::BenchError::Serialization(e) => BenchErrorVariant::ConfigError {
message: e.to_string(),
},
crate::types::BenchError::Config(msg) => {
BenchErrorVariant::ConfigError { message: msg }
}
crate::types::BenchError::Build(msg) => BenchErrorVariant::ExecutionFailed {
reason: format!("build error: {}", msg),
},
}
}
}
impl From<crate::timing::TimingError> for BenchErrorVariant {
fn from(err: crate::timing::TimingError) -> Self {
match err {
crate::timing::TimingError::NoIterations { .. } => BenchErrorVariant::InvalidIterations,
crate::timing::TimingError::Execution(msg) => {
BenchErrorVariant::ExecutionFailed { reason: msg }
}
}
}
}
#[cfg(feature = "registry")]
pub fn run_benchmark_template(
spec: crate::BenchSpec,
) -> Result<BenchReportTemplate, BenchErrorVariant> {
crate::run_benchmark(spec)
.map(Into::into)
.map_err(Into::into)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bench_spec_template_conversion() {
let sdk_spec = crate::BenchSpec {
name: "test".to_string(),
iterations: 100,
warmup: 10,
};
let template: BenchSpecTemplate = sdk_spec.clone().into();
assert_eq!(template.name, "test");
assert_eq!(template.iterations, 100);
assert_eq!(template.warmup, 10);
let back: crate::BenchSpec = template.into();
assert_eq!(back.name, sdk_spec.name);
assert_eq!(back.iterations, sdk_spec.iterations);
assert_eq!(back.warmup, sdk_spec.warmup);
}
#[test]
fn test_bench_sample_template_conversion() {
let sdk_sample = crate::BenchSample {
duration_ns: 12345,
cpu_time_ms: Some(12),
peak_memory_kb: Some(48),
process_peak_memory_kb: Some(1024),
};
let template: BenchSampleTemplate = sdk_sample.into();
assert_eq!(template.duration_ns, 12345);
assert_eq!(template.cpu_time_ms, Some(12));
assert_eq!(template.peak_memory_kb, Some(48));
assert_eq!(template.process_peak_memory_kb, Some(1024));
}
#[test]
fn test_bench_error_variant_conversion() {
let err = crate::types::BenchError::UnknownFunction(
"test_func".to_string(),
vec!["available_func".to_string()],
);
let variant: BenchErrorVariant = err.into();
match variant {
BenchErrorVariant::UnknownFunction { name } => assert_eq!(name, "test_func"),
_ => panic!("Expected UnknownFunction variant"),
}
}
}