feat: add semi-human-readable-and-writable-ir
This commit is contained in:
parent
4db6eb4317
commit
ee675de202
3 changed files with 119 additions and 23 deletions
|
@ -7,11 +7,19 @@ pub mod instruction;
|
||||||
pub type Map<K, V> = ahash::AHashMap<K, V>;
|
pub type Map<K, V> = ahash::AHashMap<K, V>;
|
||||||
pub type Set<V> = ahash::AHashSet<V>;
|
pub type Set<V> = ahash::AHashSet<V>;
|
||||||
|
|
||||||
|
/// Gives you a super well typed graph IR for a given human-readable repr.
|
||||||
|
///
|
||||||
|
/// Look at [`SemiHumanGraphIr`] and the test files in the repo at `testfiles/`
|
||||||
|
/// to see what the RON should look like.
|
||||||
|
/// No, we don't want you to write out [`GraphIr`] in full by hand.
|
||||||
|
/// That's something for the machines to do.
|
||||||
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the parsed source is not a valid graph IR.
|
/// Returns an error if the parsed source is not a valid human-readable graph IR.
|
||||||
pub fn from_ron(source: &str) -> ron::error::SpannedResult<GraphIr> {
|
pub fn from_ron(source: &str) -> ron::error::SpannedResult<GraphIr> {
|
||||||
ron::from_str(source)
|
let human_repr: SemiHumanGraphIr = ron::from_str(source)?;
|
||||||
|
Ok(human_repr.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The toplevel representation of a whole pipeline.
|
/// The toplevel representation of a whole pipeline.
|
||||||
|
@ -68,10 +76,11 @@ pub mod id {
|
||||||
/// It does **not** contain what kind of instruction this is.
|
/// It does **not** contain what kind of instruction this is.
|
||||||
/// Refer to [`crate::instruction::Kind`] for this instead.
|
/// Refer to [`crate::instruction::Kind`] for this instead.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
pub struct Instruction(Span);
|
pub struct Instruction(pub(super) Span);
|
||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
/// Where this instruction is written down.
|
/// Where this instruction is written down.
|
||||||
|
#[must_use]
|
||||||
pub fn span(&self) -> &Span {
|
pub fn span(&self) -> &Span {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
@ -81,20 +90,20 @@ pub mod id {
|
||||||
///
|
///
|
||||||
/// An **instruction** cannot run if any of these are not connected.
|
/// An **instruction** cannot run if any of these are not connected.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
pub struct Input(Socket);
|
pub struct Input(pub(super) Socket);
|
||||||
|
|
||||||
/// On an **instruction**, returns outgoing data to be fed to [`Input`]s.
|
/// On an **instruction**, returns outgoing data to be fed to [`Input`]s.
|
||||||
///
|
///
|
||||||
/// In contrast to [`Input`]s, [`Output`]s may be used or unused.
|
/// In contrast to [`Input`]s, [`Output`]s may be used or unused.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
pub struct Output(Socket);
|
pub struct Output(pub(super) Socket);
|
||||||
|
|
||||||
/// An unspecified socket on a specific **instruction**,
|
/// An unspecified socket on a specific **instruction**,
|
||||||
/// and where it is on that **instruction**.
|
/// and where it is on that **instruction**.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
pub struct Socket {
|
pub struct Socket {
|
||||||
pub belongs_to: Instruction,
|
pub belongs_to: Instruction,
|
||||||
pub index: SocketIdx,
|
pub idx: SocketIdx,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Where a [`Socket`] is on an **instruction**.
|
/// Where a [`Socket`] is on an **instruction**.
|
||||||
|
@ -106,3 +115,81 @@ pub mod id {
|
||||||
pub struct Span {
|
pub struct Span {
|
||||||
range: RangeInclusive<usize>,
|
range: RangeInclusive<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this desperately belongs into its own file, also id should get its own file
|
||||||
|
/// Semi-human-{read,writ}able [`GraphIr`] with far less useful types.
|
||||||
|
///
|
||||||
|
/// **Do not use this if you want to programatically construct IR.**
|
||||||
|
/// Instead, directly use [`GraphIr`].
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
|
pub struct SemiHumanGraphIr {
|
||||||
|
/// See [`GraphIr::instructions`], just that a simple number is used for the ID instead
|
||||||
|
/// of a proper span.
|
||||||
|
instructions: Map<usize, instruction::Kind>,
|
||||||
|
/// See [`GraphIr::edges`]. RON wants you to type the set as a list.
|
||||||
|
edges: Map<SemiHumanSocket, Set<SemiHumanSocket>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
|
pub struct SemiHumanSocket {
|
||||||
|
/// ID of the instruction this socket is on.
|
||||||
|
on: usize,
|
||||||
|
idx: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SemiHumanSocket> for id::Socket {
|
||||||
|
fn from(source: SemiHumanSocket) -> Self {
|
||||||
|
Self {
|
||||||
|
belongs_to: (id::Instruction(Span {
|
||||||
|
range: source.on..=source.on,
|
||||||
|
})),
|
||||||
|
idx: id::SocketIdx(source.idx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SemiHumanGraphIr> for GraphIr {
|
||||||
|
fn from(source: SemiHumanGraphIr) -> Self {
|
||||||
|
let edges = source.edges.clone();
|
||||||
|
Self {
|
||||||
|
instructions: source
|
||||||
|
.instructions
|
||||||
|
.into_iter()
|
||||||
|
.map(|(id, kind)| (id::Instruction(Span { range: id..=id }), kind))
|
||||||
|
.collect(),
|
||||||
|
edges: type_edges(source.edges),
|
||||||
|
// same as above, but also reverse the mapping
|
||||||
|
rev_edges: reverse_and_type_edges(edges),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_edges(
|
||||||
|
edges: Map<SemiHumanSocket, Set<SemiHumanSocket>>,
|
||||||
|
) -> Map<id::Output, Set<id::Input>> {
|
||||||
|
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<SemiHumanSocket, Set<SemiHumanSocket>>,
|
||||||
|
) -> Map<id::Input, Set<id::Output>> {
|
||||||
|
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());
|
||||||
|
rev_edges.entry(input).or_default().insert(output.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
rev_edges
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
(
|
(
|
||||||
[
|
instructions: {
|
||||||
Read((
|
0: Read((
|
||||||
source: File("testfiles/juan.png"),
|
source: File("testfiles/juan.jpg"),
|
||||||
format: Jpeg
|
format: Jpeg,
|
||||||
)),
|
)),
|
||||||
Write((
|
1: Write((
|
||||||
target: File("testfiles/out.png"),
|
target: File("testfiles/out.png"),
|
||||||
format: Png
|
format: Png,
|
||||||
))
|
)),
|
||||||
]
|
},
|
||||||
|
edges: {
|
||||||
|
(on: 0, idx: 0): [
|
||||||
|
(on: 1, idx: 0),
|
||||||
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
(
|
(
|
||||||
[
|
instructions: {
|
||||||
Read((
|
0: Read((
|
||||||
source: File("testfiles/juan.jpg"),
|
source: File("testfiles/juan.jpg"),
|
||||||
format: Jpeg
|
format: Jpeg,
|
||||||
)),
|
)),
|
||||||
Filter(Invert),
|
1: Filter(Invert),
|
||||||
Write((
|
2: Write((
|
||||||
target: File("testfiles/inverted.jpg"),
|
target: File("testfiles/inverted.png"),
|
||||||
format: Jpeg
|
format: Png,
|
||||||
))
|
)),
|
||||||
]
|
},
|
||||||
|
edges: {
|
||||||
|
(on: 0, idx: 0): [(on: 1, idx: 0)],
|
||||||
|
(on: 1, idx: 0): [(on: 2, idx: 0)],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue