use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
use crate::logic::{GlobalLocation, GlobalTranslation};
use crate::ra;
#[derive(Clone, Debug)]
pub struct Config {
pub(crate) flags: WriterFlags,
pub(crate) runtime_path: Cow<'static, str>,
pub(crate) global_struct: Option<String>,
pub(crate) resource_struct: Option<String>,
#[allow(dead_code, reason = "reminding ourselves of the future")]
pub(crate) edition: Edition,
pub(crate) rules: Vec<Rule>,
}
impl Default for Config {
fn default() -> Self {
Self::new()
}
}
impl Config {
#[must_use]
pub const fn new() -> Self {
Self {
flags: WriterFlags::INCLUDE_FUNCTIONS,
runtime_path: Cow::Borrowed("::naga_rust_rt"),
global_struct: None,
resource_struct: None,
edition: Edition::Rust2024,
rules: Vec::new(),
}
}
#[must_use]
pub fn include_functions(mut self, value: bool) -> Self {
self.flags.set(WriterFlags::INCLUDE_FUNCTIONS, value);
self
}
#[must_use]
pub fn explicit_types(mut self, value: bool) -> Self {
self.flags.set(WriterFlags::EXPLICIT_TYPES, value);
self
}
#[must_use]
pub fn raw_pointers(mut self, value: bool) -> Self {
self.flags.set(WriterFlags::RAW_POINTERS, value);
self
}
#[must_use]
pub fn public_items(mut self, value: bool) -> Self {
self.flags.set(WriterFlags::PUBLIC, value);
self
}
#[must_use]
pub fn allow_unimplemented(mut self, value: bool) -> Self {
self.flags.set(WriterFlags::ALLOW_UNIMPLEMENTED, value);
self
}
#[must_use]
pub fn runtime_path(mut self, value: impl Into<Cow<'static, str>>) -> Self {
let value = value.into();
assert!(
value.starts_with("::") || value.starts_with("crate::"),
"path should be an absolute path"
);
self.runtime_path = value;
self
}
#[must_use]
pub fn global_struct(mut self, name: impl Into<String>) -> Self {
self.global_struct = Some(name.into());
self
}
#[must_use]
pub fn resource_struct(mut self, name: impl Into<String>) -> Self {
self.resource_struct = Some(name.into());
self
}
#[must_use]
pub fn rule(mut self, rule: impl Into<Rule>) -> Self {
self.rules.push(rule.into());
self
}
}
impl Config {
pub(crate) fn functions_are_methods(&self) -> bool {
self.global_struct.is_some() || self.resource_struct.is_some()
}
pub(crate) fn impl_type(&self) -> Option<&str> {
match self.global_struct {
Some(ref name) => Some(name),
None => self.resource_struct.as_deref(),
}
}
pub(crate) fn global_field_access_expr(
&self,
module: &naga::Module,
variable: &naga::GlobalVariable,
) -> ra::Expr {
match (
GlobalTranslation::get(module, variable).location,
&self.global_struct,
) {
(GlobalLocation::Resource, Some(_)) => {
ra::Expr::NamedField(Box::new(ra::Expr::Self_), "resources".into())
}
(GlobalLocation::Resource, None) | (GlobalLocation::Variable, _) => ra::Expr::Self_,
}
}
pub(crate) fn apply_rules(&self, input: &RuleInput<'_>) -> impl Iterator<Item = &Effect> {
self.rules.iter().flat_map(
|Rule {
conditions: condition,
effects,
}| {
if condition.iter().all(|c| c.test(input)) {
effects.as_slice()
} else {
&[]
}
},
)
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct WriterFlags: u32 {
const INCLUDE_FUNCTIONS = 1 << 0;
const EXPLICIT_TYPES = 1 << 1;
const RAW_POINTERS = 1 << 2;
const PUBLIC = 1 << 3;
const ALLOW_UNIMPLEMENTED = 1 << 4;
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) enum Edition {
Rust2024,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[allow(clippy::exhaustive_structs)]
pub struct Rule {
pub conditions: Vec<Condition>,
pub effects: Vec<Effect>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Condition {
Function(String),
Struct(String),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Effect {
Derive(String),
Inline(Inline),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Inline {
Maybe,
Always,
Never,
}
pub(crate) struct RuleInput<'a> {
pub function: Option<&'a str>,
pub r#struct: Option<&'a str>,
}
impl From<(Condition, Effect)> for Rule {
fn from((c, e): (Condition, Effect)) -> Self {
Self {
conditions: vec![c],
effects: vec![e],
}
}
}
impl From<Effect> for Rule {
fn from(e: Effect) -> Self {
Self {
conditions: vec![],
effects: vec![e],
}
}
}
impl Condition {
fn test(&self, input: &RuleInput<'_>) -> bool {
match *self {
Condition::Function(ref name) => input.function == Some(name.as_str()),
Condition::Struct(ref name) => input.r#struct == Some(name.as_str()),
}
}
}