use crate::{
error::{anyhow, Result},
ty::{DescriptorType, PointerType, StorageClass, Type, Walk},
};
use fnv::FnvHashMap as HashMap;
use std::fmt;
type VariableId = u32;
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Default, Clone, Copy)]
pub struct DescriptorBinding(u32, u32);
impl DescriptorBinding {
pub fn new(desc_set: u32, bind_point: u32) -> Self {
DescriptorBinding(desc_set, bind_point)
}
pub fn set(&self) -> u32 {
self.0
}
pub fn bind(&self) -> u32 {
self.1
}
pub fn into_inner(self) -> (u32, u32) {
(self.0, self.1)
}
}
impl fmt::Display for DescriptorBinding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(set={}, bind={})", self.0, self.1)
}
}
impl fmt::Debug for DescriptorBinding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self as &dyn fmt::Display).fmt(f)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Default, Clone, Copy)]
pub struct InterfaceLocation(u32, u32);
impl InterfaceLocation {
pub fn new(loc: u32, comp: u32) -> Self {
InterfaceLocation(loc, comp)
}
pub fn loc(&self) -> u32 {
self.0
}
pub fn comp(&self) -> u32 {
self.1
}
pub fn into_inner(self) -> (u32, u32) {
(self.0, self.1)
}
}
impl fmt::Display for InterfaceLocation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(loc={}, comp={})", self.0, self.1)
}
}
impl fmt::Debug for InterfaceLocation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self as &dyn fmt::Display).fmt(f)
}
}
pub type SpecId = u32;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Variable {
Input {
name: Option<String>,
location: InterfaceLocation,
ty: Type,
},
Output {
name: Option<String>,
location: InterfaceLocation,
ty: Type,
},
Descriptor {
name: Option<String>,
desc_bind: DescriptorBinding,
desc_ty: DescriptorType,
ty: Type,
nbind: u32,
},
PushConstant {
name: Option<String>,
ty: Type,
},
SpecConstant {
name: Option<String>,
spec_id: SpecId,
ty: Type,
},
}
impl Variable {
pub fn name(&self) -> Option<&str> {
match self {
Variable::Input { name, .. } => name.as_deref(),
Variable::Output { name, .. } => name.as_deref(),
Variable::Descriptor { name, .. } => name.as_deref(),
Variable::PushConstant { name, .. } => name.as_deref(),
Variable::SpecConstant { name, .. } => name.as_deref(),
}
}
pub fn ty(&self) -> &Type {
match self {
Variable::Input { ty, .. } => ty,
Variable::Output { ty, .. } => ty,
Variable::Descriptor { ty, .. } => ty,
Variable::PushConstant { ty, .. } => ty,
Variable::SpecConstant { ty, .. } => ty,
}
}
pub fn walk<'a>(&'a self) -> Walk<'a> {
self.ty().walk()
}
}
pub struct VariableAlloc {
pub name: Option<String>,
pub store_cls: StorageClass,
pub ptr_ty: PointerType,
}
#[derive(Default)]
pub struct VariableRegistry {
var_map: HashMap<VariableId, VariableAlloc>,
}
impl VariableRegistry {
pub fn set(&mut self, id: VariableId, var: VariableAlloc) -> Result<()> {
use std::collections::hash_map::Entry;
match self.var_map.entry(id) {
Entry::Vacant(entry) => {
entry.insert(var);
Ok(())
}
_ => Err(anyhow!("variable id {} already existed", id)),
}
}
pub fn get(&self, id: VariableId) -> Result<&VariableAlloc> {
self.var_map
.get(&id)
.ok_or(anyhow!("variable id {} is not found", id))
}
pub fn iter(&self) -> impl Iterator<Item = (&VariableId, &VariableAlloc)> {
self.var_map.iter()
}
}