use core::fmt;
use std::fmt::Formatter;
use burn_tensor::DType;
use super::tensor_data_ext::TensorData;
use crate::tensor_store::ValueStore;
pub type Rank = usize;
pub type Shape = Vec<usize>;
pub type DataId = usize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValueSource {
Static(DataId),
Constant,
Dynamic,
Optional,
}
#[derive(Clone)]
pub struct Argument {
pub name: String,
pub ty: ArgType,
pub value_source: ValueSource,
pub(crate) value_store: Option<ValueStore>,
}
impl fmt::Debug for Argument {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Argument")
.field("name", &self.name)
.field("ty", &self.ty)
.field("value_source", &self.value_source)
.finish()
}
}
impl Argument {
pub fn copy_value(&mut self, other_arg: &Argument) {
self.ty = other_arg.ty.clone();
self.value_source = other_arg.value_source;
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ArgType {
Scalar(DType),
Shape(Rank),
Tensor(TensorType),
}
#[derive(Debug, Clone, PartialEq)]
pub struct TensorType {
pub dtype: DType,
pub rank: Rank,
pub static_shape: Option<Vec<usize>>,
}
impl Default for TensorType {
fn default() -> Self {
Self {
dtype: DType::F32,
rank: 0,
static_shape: None,
}
}
}
impl TensorType {
pub fn new(dtype: DType, rank: Rank, static_shape: Option<Vec<usize>>) -> Self {
Self {
dtype,
rank,
static_shape,
}
}
}
impl Default for ArgType {
fn default() -> Self {
Self::Tensor(TensorType::default())
}
}
impl ArgType {
pub fn is_scalar(&self) -> bool {
matches!(self, Self::Scalar(_))
}
pub fn is_tensor(&self) -> bool {
matches!(self, Self::Tensor(_))
}
pub fn is_shape(&self) -> bool {
matches!(self, Self::Shape(_))
}
pub fn rank(&self) -> usize {
match self {
ArgType::Scalar(_) => 0,
ArgType::Shape(_) => 1,
ArgType::Tensor(t) => t.rank,
}
}
pub fn elem_type(&self) -> DType {
match self {
ArgType::Scalar(s) => *s,
ArgType::Shape(_) => panic!("ArgType::Shape has no DType"),
ArgType::Tensor(t) => t.dtype,
}
}
pub fn static_shape(&self) -> Option<&Vec<usize>> {
match self {
ArgType::Tensor(t) => t.static_shape.as_ref(),
_ => None,
}
}
}
impl Argument {
pub fn new(name: impl Into<String>, ty: ArgType) -> Self {
let name = name.into();
let value_source = if name.is_empty() {
ValueSource::Optional
} else {
ValueSource::Dynamic
};
Self {
name,
ty,
value_source,
value_store: None,
}
}
pub fn from_name(name: impl Into<String>) -> Self {
Self::new(name, ArgType::default())
}
pub fn value(&self) -> Option<TensorData> {
if self.value_store.is_none() {
if matches!(
self.value_source,
ValueSource::Constant | ValueSource::Static(_)
) {
log::warn!(
"value() called on '{}' (value_source={:?}) but value_store is None",
self.name,
self.value_source
);
}
return None;
}
let store = self.value_store.as_ref()?;
match &self.value_source {
ValueSource::Static(data_id) => {
let result = store.get_tensor_data(*data_id);
if result.is_none() {
log::warn!(
"value() for Static({}) on '{}' returned None - store has {} tensors",
data_id,
self.name,
store.tensor_count()
);
}
result
}
ValueSource::Constant => {
let data_id = store.get_constant_data_id(&self.name);
if data_id.is_none() {
log::warn!(
"value() lookup failed for '{}': constant not found in store (constant_map has {} entries)",
self.name,
store.constant_map_len()
);
}
let data_id = data_id?;
store.get_tensor_data(data_id)
}
ValueSource::Dynamic | ValueSource::Optional => None,
}
}
pub(crate) fn set_value_store(&mut self, store: ValueStore) {
self.value_store = Some(store);
}
pub fn is_static(&self) -> bool {
matches!(self.value_source, ValueSource::Static(_))
}
pub fn is_constant(&self) -> bool {
self.value_source == ValueSource::Constant
}
pub fn is_dynamic(&self) -> bool {
self.value_source == ValueSource::Dynamic
}
pub fn is_optional(&self) -> bool {
self.value_source == ValueSource::Optional
}
pub fn to_static(&mut self) -> Result<(), crate::processor::ProcessError> {
use crate::processor::ProcessError;
if !self.is_constant() {
return Err(ProcessError::Custom(format!(
"Cannot convert {:?} argument to Static (only Constant can be converted)",
self.value_source
)));
}
let store = self.value_store.as_ref().ok_or_else(|| {
ProcessError::Custom("No value store available to look up constant".to_string())
})?;
let data_id = store.get_constant_data_id(&self.name).ok_or_else(|| {
ProcessError::Custom(format!(
"Constant node not found or has no data_id for output name: {}",
self.name
))
})?;
self.value_source = ValueSource::Static(data_id);
self.name.clear();
Ok(())
}
pub fn from_const_i64(name: impl Into<String>, value: i64) -> Self {
use crate::tensor_store::{TensorDataRef, TensorStore, ValueStore};
use std::collections::HashMap;
use std::rc::Rc;
let bytes = bytes::Bytes::copy_from_slice(&value.to_ne_bytes());
let data_ref = TensorDataRef::new(bytes, vec![], DType::I64);
let mut tensor_store = TensorStore::new();
let data_id = tensor_store.store(data_ref);
let value_store = ValueStore::new(Rc::new(tensor_store), Rc::new(HashMap::new()));
Self {
name: name.into(),
ty: ArgType::Scalar(DType::I64),
value_source: ValueSource::Static(data_id),
value_store: Some(value_store),
}
}
}