use enum_as_inner::EnumAsInner;
use num::complex::Complex64;
use quil_rs::instruction::MemoryReference;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[cfg(feature = "stubs")]
use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pyclass_complex_enum};
use qcs_api_client_grpc::models::controller::{
self, data_value as controller_memory_value, readout_values as controller_readout_values,
DataValue as ControllerMemoryValues, ReadoutValues as ControllerReadoutValues,
};
#[expect(clippy::unsafe_derive_deserialize)]
#[derive(Debug, Clone, EnumAsInner, PartialEq, Deserialize, Serialize)]
#[cfg_attr(feature = "stubs", gen_stub_pyclass_complex_enum)]
#[cfg_attr(feature = "python", pyo3::pyclass(module = "qcs_sdk.qpu"))]
pub enum ReadoutValues {
Integer(Vec<i64>),
Real(Vec<f64>),
Complex(Vec<Complex64>),
}
#[expect(clippy::unsafe_derive_deserialize)]
#[derive(Debug, Clone, EnumAsInner, PartialEq, Deserialize, Serialize)]
#[cfg_attr(feature = "stubs", gen_stub_pyclass_complex_enum)]
#[cfg_attr(feature = "python", pyo3::pyclass(module = "qcs_sdk.qpu", eq))]
pub enum MemoryValues {
Binary(Vec<u8>),
Integer(Vec<i64>),
Real(Vec<f64>),
}
#[expect(clippy::module_name_repetitions, clippy::unsafe_derive_deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(module = "qcs_sdk.qpu", name = "QPUResultData", get_all)
)]
pub struct QpuResultData {
pub(crate) mappings: HashMap<String, String>,
pub(crate) readout_values: HashMap<String, ReadoutValues>,
pub(crate) memory_values: HashMap<String, MemoryValues>,
}
impl QpuResultData {
#[must_use]
pub fn from_mappings_and_values(
mappings: HashMap<String, String>,
readout_values: HashMap<String, ReadoutValues>,
memory_values: HashMap<String, MemoryValues>,
) -> Self {
Self {
mappings,
readout_values,
memory_values,
}
}
pub(crate) fn from_controller_mappings_and_values(
mappings: &HashMap<String, String>,
readout_values: &HashMap<String, ControllerReadoutValues>,
memory_values: &HashMap<String, ControllerMemoryValues>,
) -> Self {
Self {
mappings: mappings.clone(),
readout_values: readout_values
.iter()
.map(|(key, readout_values)| {
(
key.clone(),
match &readout_values.values {
Some(controller_readout_values::Values::IntegerValues(v)) => {
ReadoutValues::Integer(
v.values.iter().copied().map(i64::from).collect(),
)
}
Some(controller_readout_values::Values::ComplexValues(v)) => {
ReadoutValues::Complex(
v.values
.iter()
.map(|c| Complex64::new(c.real.into(), c.imaginary.into()))
.collect(),
)
}
None => ReadoutValues::Integer(Vec::new()),
},
)
})
.collect(),
memory_values: memory_values
.iter()
.filter_map(|(key, memory_values)| {
memory_values.value.as_ref().map(|value| {
(
key.clone(),
match value {
controller_memory_value::Value::Binary(
controller::BinaryDataValue { data: v },
) => MemoryValues::Binary(v.clone()),
controller_memory_value::Value::Integer(
controller::IntegerDataValue { data: v },
) => MemoryValues::Integer(v.clone()),
controller_memory_value::Value::Real(
controller::RealDataValue { data: v },
) => MemoryValues::Real(v.clone()),
},
)
})
})
.collect(),
}
}
#[must_use]
pub fn get_values_for_memory_reference(
&self,
reference: &MemoryReference,
) -> Option<&ReadoutValues> {
self.mappings
.get(&reference.to_string())
.and_then(|key| self.readout_values.get(key))
}
#[must_use]
pub fn mappings(&self) -> &HashMap<String, String> {
&self.mappings
}
#[must_use]
pub fn readout_values(&self) -> &HashMap<String, ReadoutValues> {
&self.readout_values
}
#[must_use]
pub fn memory_values(&self) -> &HashMap<String, MemoryValues> {
&self.memory_values
}
}