feat(ir): implement resolve functionality (untested)
This commit is contained in:
parent
b67f517d89
commit
6e73ff9c5a
8 changed files with 203 additions and 101 deletions
70
Cargo.lock
generated
70
Cargo.lock
generated
|
@ -8,20 +8,6 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ahash"
|
|
||||||
version = "0.8.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"getrandom",
|
|
||||||
"once_cell",
|
|
||||||
"serde",
|
|
||||||
"version_check",
|
|
||||||
"zerocopy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
|
@ -287,17 +273,6 @@ dependencies = [
|
||||||
"spin",
|
"spin",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.2.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gif"
|
name = "gif"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
|
@ -346,7 +321,6 @@ dependencies = [
|
||||||
name = "ir"
|
name = "ir"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
|
||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -366,12 +340,6 @@ version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.152"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.11"
|
version = "0.4.11"
|
||||||
|
@ -422,12 +390,6 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "once_cell"
|
|
||||||
version = "1.19.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.17.10"
|
version = "0.17.10"
|
||||||
|
@ -587,18 +549,6 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "weezl"
|
name = "weezl"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
@ -671,26 +621,6 @@ version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy"
|
|
||||||
version = "0.7.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
|
||||||
dependencies = [
|
|
||||||
"zerocopy-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy-derive"
|
|
||||||
version = "0.7.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-inflate"
|
name = "zune-inflate"
|
||||||
version = "0.2.54"
|
version = "0.2.54"
|
||||||
|
|
|
@ -6,7 +6,6 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ahash = { version = "0.8.7", features = ["serde"] }
|
|
||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
serde = { version = "1.0.193", features = ["derive"] }
|
serde = { version = "1.0.193", features = ["derive"] }
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ use crate::Span;
|
||||||
///
|
///
|
||||||
/// 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, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct Instruction(pub(super) Span);
|
pub struct Instruction(pub(super) Span);
|
||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
|
@ -39,23 +39,37 @@ impl Instruction {
|
||||||
/// On an **instruction**, accepts incoming data.
|
/// On an **instruction**, accepts incoming data.
|
||||||
///
|
///
|
||||||
/// 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, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct Input(pub(super) Socket);
|
pub struct Input(pub(super) Socket);
|
||||||
|
|
||||||
|
impl Input {
|
||||||
|
#[must_use]
|
||||||
|
pub fn socket(&self) -> &Socket {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct Output(pub(super) Socket);
|
pub struct Output(pub(super) Socket);
|
||||||
|
|
||||||
|
impl Output {
|
||||||
|
#[must_use]
|
||||||
|
pub fn socket(&self) -> &Socket {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct Socket {
|
pub struct Socket {
|
||||||
pub belongs_to: Instruction,
|
pub belongs_to: Instruction,
|
||||||
pub idx: SocketIdx,
|
pub idx: SocketIdx,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Where a [`Socket`] is on an **instruction**.
|
/// Where a [`Socket`] is on an **instruction**.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct SocketIdx(pub u16);
|
pub struct SocketIdx(pub u16);
|
||||||
|
|
|
@ -3,8 +3,10 @@ use serde::{Deserialize, Serialize};
|
||||||
pub mod read;
|
pub mod read;
|
||||||
pub mod write;
|
pub mod write;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
|
// TODO: `read::Read` and `write::Write` hold real values atm -- they should actually
|
||||||
|
// point to `Const` instructions instead (which are... yet to be done...)
|
||||||
Read(read::Read),
|
Read(read::Read),
|
||||||
Write(write::Write),
|
Write(write::Write),
|
||||||
Math(Math),
|
Math(Math),
|
||||||
|
@ -13,7 +15,7 @@ pub enum Kind {
|
||||||
Filter(Filter),
|
Filter(Filter),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub enum Math {
|
pub enum Math {
|
||||||
Add,
|
Add,
|
||||||
Subtract,
|
Subtract,
|
||||||
|
@ -21,7 +23,7 @@ pub enum Math {
|
||||||
Divide,
|
Divide,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub enum Blend {
|
pub enum Blend {
|
||||||
Normal,
|
Normal,
|
||||||
Multiply,
|
Multiply,
|
||||||
|
@ -34,14 +36,46 @@ pub enum Blend {
|
||||||
Lighten,
|
Lighten,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub enum Noise {
|
pub enum Noise {
|
||||||
Perlin,
|
Perlin,
|
||||||
Simplex,
|
Simplex,
|
||||||
Voronoi,
|
Voronoi,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub enum Filter {
|
pub enum Filter {
|
||||||
Invert,
|
Invert,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: given that this basically matches on all instructions, we may need to use
|
||||||
|
// the visitor pattern in future here, or at least get them behind traits
|
||||||
|
// which should allow far more nuanced description
|
||||||
|
impl Kind {
|
||||||
|
/// Returns how many sockets this kind of instruction has.
|
||||||
|
#[must_use]
|
||||||
|
pub fn socket_count(&self) -> SocketCount {
|
||||||
|
match self {
|
||||||
|
Self::Read(_) => (0, 1),
|
||||||
|
Self::Write(_) => (1, 0),
|
||||||
|
Self::Math(_) | Self::Blend(_) => (2, 1),
|
||||||
|
Self::Noise(_) => {
|
||||||
|
todo!("how many arguments does noise take? how many outputs does it have?")
|
||||||
|
}
|
||||||
|
Self::Filter(Filter::Invert) => (1, 1),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// How many sockets are on an instruction?
|
||||||
|
pub struct SocketCount {
|
||||||
|
pub inputs: u16,
|
||||||
|
pub outputs: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(u16, u16)> for SocketCount {
|
||||||
|
fn from((inputs, outputs): (u16, u16)) -> Self {
|
||||||
|
Self { inputs, outputs }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct Read {
|
pub struct Read {
|
||||||
pub source: SourceType,
|
pub source: SourceType,
|
||||||
pub format: SourceFormat,
|
pub format: SourceFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub enum SourceType {
|
pub enum SourceType {
|
||||||
File(PathBuf),
|
File(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub enum SourceFormat {
|
pub enum SourceFormat {
|
||||||
Jpeg,
|
Jpeg,
|
||||||
Png,
|
Png,
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct Write {
|
pub struct Write {
|
||||||
pub target: TargetType,
|
pub target: TargetType,
|
||||||
pub format: TargetFormat,
|
pub format: TargetFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub enum TargetType {
|
pub enum TargetType {
|
||||||
File(PathBuf),
|
File(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub enum TargetFormat {
|
pub enum TargetFormat {
|
||||||
Jpeg,
|
Jpeg,
|
||||||
Png,
|
Png,
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
use std::ops::RangeInclusive;
|
use std::{
|
||||||
|
collections::{BTreeMap, BTreeSet},
|
||||||
|
ops::RangeInclusive,
|
||||||
|
};
|
||||||
|
|
||||||
|
use instruction::SocketCount;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod id;
|
pub mod id;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
pub mod semi_human;
|
pub mod semi_human;
|
||||||
|
|
||||||
pub type Map<K, V> = ahash::AHashMap<K, V>;
|
pub type Map<K, V> = std::collections::BTreeMap<K, V>;
|
||||||
pub type Set<V> = ahash::AHashSet<V>;
|
pub type Set<V> = std::collections::BTreeSet<V>;
|
||||||
|
|
||||||
/// Gives you a super well typed graph IR for a given human-readable repr.
|
/// Gives you a super well typed graph IR for a given human-readable repr.
|
||||||
///
|
///
|
||||||
|
@ -64,10 +68,127 @@ pub struct GraphIr {
|
||||||
/// How the data flows forward. **Dependencies** map to **dependents** here.
|
/// How the data flows forward. **Dependencies** map to **dependents** here.
|
||||||
edges: Map<id::Output, Set<id::Input>>,
|
edges: Map<id::Output, Set<id::Input>>,
|
||||||
/// How the data flows backward. **Dependents** map to **dependencies** here.
|
/// How the data flows backward. **Dependents** map to **dependencies** here.
|
||||||
rev_edges: Map<id::Input, Set<id::Output>>,
|
rev_edges: Map<id::Input, id::Output>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
impl GraphIr {
|
||||||
pub struct Span {
|
// TODO: this function, but actually the whole module, screams for tests
|
||||||
range: RangeInclusive<usize>,
|
/// Returns the instruction corresponding to the given ID.
|
||||||
|
/// Returns [`None`] if there is no such instruction in this graph IR.
|
||||||
|
///
|
||||||
|
/// Theoretically this could be fixed easily at the expense of some memory
|
||||||
|
/// by just incrementing and storing some global counter,
|
||||||
|
/// however, at the moment there's no compelling reason
|
||||||
|
/// to actually have multiple [`GraphIr`]s at one point in time.
|
||||||
|
/// Open an issue if that poses a problem for you.
|
||||||
|
#[must_use]
|
||||||
|
pub fn resolve<'ir>(&'ir self, id: &id::Instruction) -> Option<Instruction<'ir>> {
|
||||||
|
let (id, kind) = self.instructions.get_key_value(id)?;
|
||||||
|
|
||||||
|
// just try each slot and see if it's connected
|
||||||
|
// very crude, but it works for a proof of concept
|
||||||
|
let SocketCount { inputs, outputs } = kind.socket_count();
|
||||||
|
let socket = |id: &id::Instruction, idx| id::Socket {
|
||||||
|
belongs_to: id.clone(),
|
||||||
|
// impossible since the length is limited to a u16 already
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
idx: id::SocketIdx(idx as u16),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut inputs_from = vec![None; inputs.into()];
|
||||||
|
for (idx, slot) in inputs_from.iter_mut().enumerate() {
|
||||||
|
let input = id::Input(socket(id, idx));
|
||||||
|
*slot = self.rev_edges.get(&input);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut outputs_to = vec![None; outputs.into()];
|
||||||
|
for (idx, slot) in outputs_to.iter_mut().enumerate() {
|
||||||
|
let output = id::Output(socket(id, idx));
|
||||||
|
*slot = self.edges.get(&output);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Instruction {
|
||||||
|
id,
|
||||||
|
kind,
|
||||||
|
inputs_from,
|
||||||
|
outputs_to,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the instruction this input belongs to.
|
||||||
|
///
|
||||||
|
/// The same caveats as for [`GraphIr::resolve`] apply.
|
||||||
|
#[must_use]
|
||||||
|
pub fn owner_of_input<'ir>(&'ir self, input: &id::Input) -> Option<Instruction<'ir>> {
|
||||||
|
self.resolve(&input.socket().belongs_to)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the instruction this output belongs to.
|
||||||
|
///
|
||||||
|
/// The same caveats as for [`GraphIr::resolve`] apply.
|
||||||
|
#[must_use]
|
||||||
|
pub fn owner_of_output<'ir>(&'ir self, output: &id::Output) -> Option<Instruction<'ir>> {
|
||||||
|
self.resolve(&output.socket().belongs_to)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn topological_sort(&self) -> Vec<Instruction> {
|
||||||
|
// count how many incoming edges each vertex has
|
||||||
|
// chances are the BTreeMap is overkill
|
||||||
|
let incoming_counts: BTreeMap<_, _> = self
|
||||||
|
.rev_edges
|
||||||
|
.iter()
|
||||||
|
.map(|(input, _)| (self.owner_of_input(input), 1))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A full instruction in context, with its inputs and outputs.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Instruction<'ir> {
|
||||||
|
pub id: &'ir id::Instruction,
|
||||||
|
pub kind: &'ir instruction::Kind,
|
||||||
|
|
||||||
|
// can't have these two public since then a user might corrupt their length
|
||||||
|
inputs_from: Vec<Option<&'ir id::Output>>,
|
||||||
|
outputs_to: Vec<Option<&'ir BTreeSet<id::Input>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ir> Instruction<'ir> {
|
||||||
|
/// Where this instruction gets its inputs from.
|
||||||
|
///
|
||||||
|
/// [`None`] means that this input is unfilled,
|
||||||
|
/// and must be filled before the instruction can be ran.
|
||||||
|
#[must_use]
|
||||||
|
pub fn inputs_from(&self) -> &[Option<&'ir id::Output>] {
|
||||||
|
&self.inputs_from
|
||||||
|
}
|
||||||
|
|
||||||
|
/// To whom outputs are sent. [`None`] means that this output is unused.
|
||||||
|
#[must_use]
|
||||||
|
pub fn outputs_to(&self) -> &[Option<&'ir BTreeSet<id::Input>>] {
|
||||||
|
&self.outputs_to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Some part referred to in source code.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
|
pub struct Span {
|
||||||
|
// would love to use an actual [`std::ops::RangeInclusive`], but those don't implement
|
||||||
|
// `PartialOrd` and `Ord` unfortunately
|
||||||
|
/// At which byte this span starts, inclusively.
|
||||||
|
pub from: usize,
|
||||||
|
/// At which byte this span ends, inclusively.
|
||||||
|
pub to: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RangeInclusive<usize>> for Span {
|
||||||
|
fn from(range: RangeInclusive<usize>) -> Self {
|
||||||
|
Self {
|
||||||
|
from: *range.start(),
|
||||||
|
to: *range.end(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,12 @@ pub struct GraphIr {
|
||||||
/// See [`crate::GraphIr::instructions`], just that a simple number is used for the ID instead
|
/// See [`crate::GraphIr::instructions`], just that a simple number is used for the ID instead
|
||||||
/// of a proper span.
|
/// of a proper span.
|
||||||
pub(crate) instructions: Map<usize, instruction::Kind>,
|
pub(crate) instructions: Map<usize, instruction::Kind>,
|
||||||
/// See [`crate::GraphIr::edges`]. RON wants you to type the set as if it were a list.
|
/// See [`crate::GraphIr::edges`], the forward edges.
|
||||||
|
/// RON wants you to type the set as if it were a list.
|
||||||
pub(crate) edges: Map<Socket, Set<Socket>>,
|
pub(crate) edges: Map<Socket, Set<Socket>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
|
||||||
pub struct Socket {
|
pub struct Socket {
|
||||||
/// ID of the instruction this socket is on.
|
/// ID of the instruction this socket is on.
|
||||||
pub(crate) on: usize,
|
pub(crate) on: usize,
|
||||||
|
@ -36,7 +37,8 @@ impl From<Socket> for id::Socket {
|
||||||
fn from(source: Socket) -> Self {
|
fn from(source: Socket) -> Self {
|
||||||
Self {
|
Self {
|
||||||
belongs_to: (id::Instruction(Span {
|
belongs_to: (id::Instruction(Span {
|
||||||
range: source.on..=source.on,
|
from: source.on,
|
||||||
|
to: source.on,
|
||||||
})),
|
})),
|
||||||
idx: id::SocketIdx(source.idx),
|
idx: id::SocketIdx(source.idx),
|
||||||
}
|
}
|
||||||
|
@ -50,10 +52,9 @@ impl From<GraphIr> for crate::GraphIr {
|
||||||
instructions: source
|
instructions: source
|
||||||
.instructions
|
.instructions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, kind)| (id::Instruction(Span { range: id..=id }), kind))
|
.map(|(id, kind)| (id::Instruction(Span { from: id, to: id }), kind))
|
||||||
.collect(),
|
.collect(),
|
||||||
edges: type_edges(source.edges),
|
edges: type_edges(source.edges),
|
||||||
// same as above, but also reverse the mapping
|
|
||||||
rev_edges: reverse_and_type_edges(edges),
|
rev_edges: reverse_and_type_edges(edges),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +71,7 @@ fn type_edges(edges: Map<Socket, Set<Socket>>) -> Map<id::Output, Set<id::Input>
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reverse_and_type_edges(edges: Map<Socket, Set<Socket>>) -> Map<id::Input, Set<id::Output>> {
|
fn reverse_and_type_edges(edges: Map<Socket, Set<Socket>>) -> Map<id::Input, id::Output> {
|
||||||
edges
|
edges
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold(Map::new(), |mut rev_edges, (output, inputs)| {
|
.fold(Map::new(), |mut rev_edges, (output, inputs)| {
|
||||||
|
@ -78,7 +79,10 @@ fn reverse_and_type_edges(edges: Map<Socket, Set<Socket>>) -> Map<id::Input, Set
|
||||||
|
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
let input = id::Input(input.into());
|
let input = id::Input(input.into());
|
||||||
rev_edges.entry(input).or_default().insert(output.clone());
|
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
|
rev_edges
|
||||||
|
|
Loading…
Reference in a new issue