//! The midterm solution for source representation, until we've got a nice source frontend. //! //! Sacrifices type expressivity for the sake of typability in [RON] files. //! //! **If you want to construct a graph IR programmatically, //! use [`crate::GraphIr`] directly instead, //! as it gives you more control to specify where your instructions came from.** //! //! [RON]: https://docs.rs/ron/latest/ron/ use serde::{Deserialize, Serialize}; use crate::{id, instruction, Map, Set}; /// Semi-human-{read,writ}able [`crate::GraphIr`] with far less useful types. /// /// **Do not use this if you want to programatically construct IR.** /// Instead, directly use [`crate::GraphIr`]. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct GraphIr { /// See [`crate::GraphIr::instructions`], just that a simple number is used for the ID instead pub(crate) instructions: Map, /// See [`crate::GraphIr::edges`], the forward edges. /// RON wants you to type the set as if it were a list. pub(crate) edges: Map>, } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] pub struct Socket { /// ID of the instruction this socket is on. pub(crate) on: u64, pub(crate) idx: u16, } impl From for id::Socket { fn from(source: Socket) -> Self { Self { belongs_to: id::Instruction(source.on), idx: id::SocketIdx(source.idx), } } } impl From for crate::GraphIr { fn from(source: GraphIr) -> Self { let edges = source.edges.clone(); Self { instructions: source .instructions .into_iter() .map(|(id, kind)| (id::Instruction(id), kind)) .collect(), edges: type_edges(source.edges), rev_edges: reverse_and_type_edges(edges), } } } fn type_edges(edges: Map>) -> Map> { edges .into_iter() .map(|(output, inputs)| { let output = id::Output(output.into()); let inputs = inputs.into_iter().map(Into::into).map(id::Input).collect(); (output, inputs) }) .collect() } fn reverse_and_type_edges(edges: Map>) -> Map { edges .into_iter() .fold(Map::new(), |mut rev_edges, (output, inputs)| { let output = id::Output(output.into()); for input in inputs { let input = id::Input(input.into()); let previous = rev_edges.insert(input, output.clone()); if let Some(previous) = previous { panic!("two or more outputs referred to the same input {previous:#?} — handle me better later with a TryFrom impl"); } } rev_edges }) }