use std::{collections::HashMap,
fmt::Debug,
ops::{AddAssign, Deref, DerefMut}};
use serde::{Deserialize, Serialize};
use super::*;
use crate::{tui::DEBUG_SHOW_PIPELINE_EXPANDED, *};
#[macro_export]
macro_rules! render_pipeline {
(
@new $arg_z_order: expr
=> $( /* Start a repetition. */
$element:expr /* Expression. */
) /* End repetition. */
, /* Comma separated. */
* /* Zero or more times. */
) => {
{
let mut render_pipeline = RenderPipeline::default();
$(
match render_pipeline.entry($arg_z_order) {
std::collections::hash_map::Entry::Occupied(mut entry) => {
entry.get_mut().list.push($element);
}
std::collections::hash_map::Entry::Vacant(entry) => {
entry.insert(render_ops!(@new $arg_z_order => $element));
}
}
)*
render_pipeline
}
};
(
@push_into $arg_pipeline:ident at $arg_z_order: expr
=> $($element:expr),+
) => {
$(
match $arg_pipeline.entry($arg_z_order) {
std::collections::hash_map::Entry::Occupied(mut entry) => {
entry.get_mut().list.push($element);
}
std::collections::hash_map::Entry::Vacant(entry) => {
entry.insert(render_ops!(@new $arg_z_order => $element));
}
}
)*
};
(@join_and_drop $($element:expr),+) => {{
let mut pipeline = RenderPipeline::default();
$(
pipeline.join_into($element);
)*
pipeline
}};
(@new_empty) => {
RenderPipeline::default()
};
}
#[derive(Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct RenderPipeline {
pub pipeline_map: PipelineMap,
}
type PipelineMap = HashMap<ZOrder, RenderOps>;
impl RenderPipeline {
pub fn join_into(&mut self, mut rhs: RenderPipeline) {
for (z_order, mut render_ops) in rhs.drain() {
match self.entry(z_order) {
std::collections::hash_map::Entry::Occupied(mut entry) => {
entry.get_mut().append(&mut render_ops.list);
}
std::collections::hash_map::Entry::Vacant(entry) => {
entry.insert(render_ops);
}
}
}
}
pub fn push(&mut self, z_order: &ZOrder, cmd_wrapper: RenderOp) -> &mut Self {
match self.entry(*z_order) {
std::collections::hash_map::Entry::Occupied(mut entry) => {
entry.get_mut().push(cmd_wrapper);
}
std::collections::hash_map::Entry::Vacant(entry) => {
entry.insert(render_ops!(@new *z_order => cmd_wrapper));
}
}
self
}
pub async fn paint(&self, flush_kind: FlushKind, shared_tw_data: &SharedTWData) {
paint(self, flush_kind, shared_tw_data).await;
}
}
pub mod z_order_impl {
use super::*;
pub const RENDER_ORDERED_Z_ORDER_ARRAY: [ZOrder; 4] =
[ZOrder::Normal, ZOrder::High, ZOrder::Caret, ZOrder::Glass];
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum ZOrder {
Normal,
High,
Caret,
Glass,
}
impl Default for ZOrder {
fn default() -> Self { Self::Normal }
}
}
pub use z_order_impl::*;
mod render_pipeline_helpers {
use super::*;
impl Deref for RenderPipeline {
type Target = PipelineMap;
fn deref(&self) -> &Self::Target { &self.pipeline_map }
}
impl DerefMut for RenderPipeline {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.pipeline_map }
}
impl Debug for RenderPipeline {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut vec_lines: Vec<String> = vec![];
if DEBUG_SHOW_PIPELINE_EXPANDED {
for (z_order, render_ops) in &**self {
let line: String = format!("[{:?}] {:?}", z_order, render_ops);
vec_lines.push(line);
}
} else {
for (z_order, render_ops) in &**self {
let line: String = format!("[{:?}] {:?} ops", z_order, render_ops.len());
vec_lines.push(line);
}
}
write!(f, " - {}", vec_lines.join("\n - "))
}
}
impl AddAssign for RenderPipeline {
fn add_assign(&mut self, other: RenderPipeline) { self.join_into(other); }
}
impl AddAssign<(ZOrder, RenderOp)> for RenderPipeline {
fn add_assign(&mut self, other: (ZOrder, RenderOp)) { self.push(&other.0, other.1); }
}
}