mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-10-30 14:01:39 +00:00
Another iteration of internal tracking
This commit is contained in:
parent
0dcd0c449d
commit
444220c6eb
@ -22,107 +22,9 @@ use std::{
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::{BitOr, Range},
|
||||
vec::Drain,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RangedStates<I, T> {
|
||||
ranges: Vec<(Range<I>, T)>,
|
||||
}
|
||||
|
||||
pub type TextureLayerStates = RangedStates<hal::image::Layer, TextureUsage>;
|
||||
pub type TextureStates2 = RangedStates<hal::image::Level, TextureLayerStates>;
|
||||
|
||||
impl<I: Copy + PartialOrd, T: Clone> RangedStates<I, T> {
|
||||
fn isolate(&mut self, index: Range<I>) -> &mut T {
|
||||
let mut pos = self.ranges
|
||||
.iter()
|
||||
.position(|&(ref range, _)| index.start >= range.start)
|
||||
.unwrap();
|
||||
let base_range = self.ranges[pos].0.clone();
|
||||
assert!(index.end <= base_range.end);
|
||||
if base_range.start < index.start {
|
||||
let value = ((base_range.start .. index.start), self.ranges[pos].1.clone());
|
||||
self.ranges.insert(pos, value);
|
||||
pos += 1;
|
||||
self.ranges[pos].0.start = index.start;
|
||||
}
|
||||
if base_range.end > index.end {
|
||||
let value = ((index.end .. base_range.end), self.ranges[pos].1.clone());
|
||||
self.ranges.insert(pos + 1, value);
|
||||
self.ranges[pos].0.end = index.end;
|
||||
}
|
||||
&mut self.ranges[pos].1
|
||||
}
|
||||
}
|
||||
|
||||
impl TextureStates2 {
|
||||
fn change_state(
|
||||
&mut self, level: hal::image::Level, layer: hal::image::Layer, usage: TextureUsage
|
||||
) -> Option<TextureUsage> {
|
||||
let layer_states = self.isolate(level .. level + 1);
|
||||
let cur_usage = layer_states.isolate(layer .. layer + 1);
|
||||
if *cur_usage != usage {
|
||||
Some(mem::replace(cur_usage, usage))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub enum PlaneStates<T> {
|
||||
Single(T),
|
||||
Multi(Vec<(Range<hal::image::Layer>, T)>),
|
||||
}
|
||||
|
||||
impl<T> Default for PlaneStates<T> {
|
||||
fn default() -> Self {
|
||||
PlaneStates::Multi(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DepthStencilState {
|
||||
depth: TextureUsage,
|
||||
stencil: TextureUsage,
|
||||
}
|
||||
|
||||
pub struct TextureStates {
|
||||
color_mips: ArrayVec<[PlaneStates<TextureUsage>; MAX_MIP_LEVELS]>,
|
||||
depth_stencil: PlaneStates<DepthStencilState>,
|
||||
}
|
||||
|
||||
impl TextureStates {
|
||||
fn change<'a>(
|
||||
&mut self,
|
||||
what: hal::image::SubresourceRange,
|
||||
usage: TextureUsage,
|
||||
permit: TrackPermit,
|
||||
fun: impl FnMut(hal::image::SubresourceRange, Tracktion<TextureUsage>),
|
||||
) {
|
||||
/*if what.aspects.contains(hal::format::Aspects::COLOR) {
|
||||
for level in what.levels.clone() {
|
||||
match self.color_mips[level as usize] {
|
||||
PlaneStates::Single(ref mut cur_usage) => {
|
||||
assert_eq!(what.layers, 0 .. 1);
|
||||
if *cur_usage != usage {
|
||||
let sub = hal::image::SubresourceRange {
|
||||
aspects: hal::format::Aspects::COLOR,
|
||||
levels: level .. level + 1,
|
||||
layers: 0 .. 1,
|
||||
};
|
||||
fun(sub, *cur_usage);
|
||||
*cur_usage = usage;
|
||||
}
|
||||
}
|
||||
PlaneStates::Multi(ref mut layers) => {
|
||||
let pos =
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[allow(unused)]
|
||||
@ -189,7 +91,7 @@ impl GenericUsage for DummyUsage {
|
||||
}
|
||||
|
||||
/// A single unit of state tracking.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Unit<U> {
|
||||
init: U,
|
||||
last: U,
|
||||
@ -228,14 +130,7 @@ impl<U: Copy + BitOr<Output=U> + PartialEq + GenericUsage> Unit<U> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Resource<S> {
|
||||
ref_count: RefCount,
|
||||
state: S,
|
||||
epoch: Epoch,
|
||||
}
|
||||
|
||||
//TODO: consider having `I` as an associated type of `U`?
|
||||
//TODO: consider having `I` as an associated type of `S`?
|
||||
#[derive(Debug)]
|
||||
pub struct Tracker<I, S> {
|
||||
/// An association of known resource indices with their tracked states.
|
||||
@ -300,7 +195,7 @@ impl<I: TypedId, S> Tracker<I, S> {
|
||||
}
|
||||
|
||||
/// Remove an id from the tracked map.
|
||||
pub(crate) fn remove(&mut self, id: I) -> bool {
|
||||
pub fn remove(&mut self, id: I) -> bool {
|
||||
match self.map.remove(&id.index()) {
|
||||
Some(resource) => {
|
||||
assert_eq!(resource.epoch, id.epoch());
|
||||
@ -455,7 +350,6 @@ impl<I: Copy + TypedId, U: Copy + GenericUsage + BitOr<Output = U> + PartialEq>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub type BufferTracker = Tracker<BufferId, Unit<BufferUsage>>;
|
||||
pub type TextureTracker = Tracker<TextureId, Unit<TextureUsage>>;
|
||||
pub type TextureViewTracker = Tracker<TextureViewId, Unit<DummyUsage>>;
|
||||
@ -494,3 +388,515 @@ impl TrackerSet {
|
||||
self.bind_groups.consume_by_extend(&other.bind_groups).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait ResourceState: Clone + Default {
|
||||
type Id: Copy + TypedId;
|
||||
type Selector;
|
||||
type Usage;
|
||||
|
||||
fn query(
|
||||
&self,
|
||||
selector: Self::Selector,
|
||||
) -> Option<Self::Usage>;
|
||||
|
||||
fn change(
|
||||
&mut self,
|
||||
id: Self::Id,
|
||||
selector: Self::Selector,
|
||||
usage: Self::Usage,
|
||||
output: Option<&mut Vec<PendingTransition<Self>>>,
|
||||
) -> Result<(), PendingTransition<Self>>;
|
||||
|
||||
fn merge(
|
||||
&mut self,
|
||||
id: Self::Id,
|
||||
other: &Self,
|
||||
stitch: Stitch,
|
||||
output: Option<&mut Vec<PendingTransition<Self>>>,
|
||||
) -> Result<(), PendingTransition<Self>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Resource<S> {
|
||||
ref_count: RefCount,
|
||||
state: S,
|
||||
epoch: Epoch,
|
||||
}
|
||||
|
||||
pub struct PendingTransition<S: ResourceState> {
|
||||
pub id: S::Id,
|
||||
pub selector: S::Selector,
|
||||
pub usage: Range<S::Usage>,
|
||||
}
|
||||
|
||||
struct ResourceTracker<S: ResourceState> {
|
||||
/// An association of known resource indices with their tracked states.
|
||||
map: FastHashMap<Index, Resource<S>>,
|
||||
/// Temporary storage for collecting transitions.
|
||||
temp: Vec<PendingTransition<S>>,
|
||||
}
|
||||
|
||||
impl<S: ResourceState> ResourceTracker<S> {
|
||||
pub fn new() -> Self {
|
||||
ResourceTracker {
|
||||
map: FastHashMap::default(),
|
||||
temp: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove an id from the tracked map.
|
||||
pub fn remove(&mut self, id: S::Id) -> bool {
|
||||
match self.map.remove(&id.index()) {
|
||||
Some(resource) => {
|
||||
assert_eq!(resource.epoch, id.epoch());
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an iterator over used resources keys.
|
||||
pub fn used<'a>(&'a self) -> impl 'a + Iterator<Item = S::Id> {
|
||||
self.map
|
||||
.iter()
|
||||
.map(|(&index, resource)| S::Id::new(index, resource.epoch))
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.map.clear();
|
||||
}
|
||||
|
||||
/// Initialize a resource to be used.
|
||||
pub fn init(
|
||||
&mut self,
|
||||
id: S::Id,
|
||||
ref_count: &RefCount,
|
||||
selector: S::Selector,
|
||||
default: S::Usage,
|
||||
) -> bool {
|
||||
let mut state = S::default();
|
||||
let _ = state.change(
|
||||
id,
|
||||
selector,
|
||||
default,
|
||||
None,
|
||||
);
|
||||
self.map
|
||||
.insert(id.index(), Resource {
|
||||
ref_count: ref_count.clone(),
|
||||
state,
|
||||
epoch: id.epoch(),
|
||||
})
|
||||
.is_none()
|
||||
}
|
||||
|
||||
/// Query a resource selector. Returns `Some(Usage)` only if
|
||||
/// this usage is consistent across the given selector.
|
||||
pub fn query(
|
||||
&mut self,
|
||||
id: S::Id,
|
||||
selector: S::Selector,
|
||||
) -> Option<S::Usage> {
|
||||
let res = self.map.get(&id.index())?;
|
||||
assert_eq!(res.epoch, id.epoch());
|
||||
res.state.query(selector)
|
||||
}
|
||||
|
||||
fn grab<'a>(
|
||||
map: &'a mut FastHashMap<Index, Resource<S>>,
|
||||
id: S::Id,
|
||||
ref_count: &RefCount,
|
||||
) -> &'a mut Resource<S> {
|
||||
match map.entry(id.index()) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(Resource {
|
||||
ref_count: ref_count.clone(),
|
||||
state: S::default(),
|
||||
epoch: id.epoch(),
|
||||
})
|
||||
}
|
||||
Entry::Occupied(e) => {
|
||||
assert_eq!(e.get().epoch, id.epoch());
|
||||
e.into_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend the usage of a specified resource.
|
||||
pub fn change_extend(
|
||||
&mut self,
|
||||
id: S::Id,
|
||||
ref_count: &RefCount,
|
||||
selector: S::Selector,
|
||||
usage: S::Usage,
|
||||
) -> Result<(), PendingTransition<S>> {
|
||||
Self::grab(&mut self.map, id, ref_count)
|
||||
.state.change(id, selector, usage, None)
|
||||
}
|
||||
|
||||
/// Replace the usage of a specified resource.
|
||||
pub fn change_replace(
|
||||
&mut self,
|
||||
id: S::Id,
|
||||
ref_count: &RefCount,
|
||||
selector: S::Selector,
|
||||
usage: S::Usage,
|
||||
) -> Result<Drain<PendingTransition<S>>, PendingTransition<S>> {
|
||||
let res = Self::grab(&mut self.map, id, ref_count);
|
||||
res.state.change(id, selector, usage, Some(&mut self.temp))?;
|
||||
Ok(self.temp.drain(..))
|
||||
}
|
||||
|
||||
/// Merge another tacker into `self` by extending the current states
|
||||
/// without any transitions.
|
||||
pub fn merge_extend(
|
||||
&mut self, other: &Self
|
||||
) -> Result<(), PendingTransition<S>> {
|
||||
for (&index, new) in other.map.iter() {
|
||||
match self.map.entry(index) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(new.clone());
|
||||
}
|
||||
Entry::Occupied(e) => {
|
||||
assert_eq!(e.get().epoch, new.epoch);
|
||||
let id = S::Id::new(index, new.epoch);
|
||||
e.into_mut().state.merge(id, &new.state, Stitch::Last, None)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Merge another tacker, adding it's transitions to `self`.
|
||||
/// Transitions the current usage to the new one.
|
||||
pub fn merge_replace<'a>(
|
||||
&'a mut self,
|
||||
other: &'a Self,
|
||||
stitch: Stitch,
|
||||
) -> Result<Drain<PendingTransition<S>>, PendingTransition<S>> {
|
||||
for (&index, new) in other.map.iter() {
|
||||
match self.map.entry(index) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(new.clone());
|
||||
}
|
||||
Entry::Occupied(e) => {
|
||||
assert_eq!(e.get().epoch, new.epoch);
|
||||
let id = S::Id::new(index, new.epoch);
|
||||
e.into_mut().state.merge(id, &new.state, stitch, Some(&mut self.temp))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(self.temp.drain(..))
|
||||
}
|
||||
|
||||
pub fn use_extend<'a, T: 'a + Borrow<RefCount>>(
|
||||
&mut self,
|
||||
storage: &'a Storage<T, S::Id>,
|
||||
id: S::Id,
|
||||
selector: S::Selector,
|
||||
usage: S::Usage,
|
||||
) -> Result<&'a T, S::Usage> {
|
||||
let item = &storage[id];
|
||||
self.change_extend(id, item.borrow(), selector, usage)
|
||||
.map(|()| item)
|
||||
.map_err(|pending| pending.usage.start)
|
||||
}
|
||||
|
||||
pub fn use_replace<'a, T: 'a + Borrow<RefCount>>(
|
||||
&mut self,
|
||||
storage: &'a Storage<T, S::Id>,
|
||||
id: S::Id,
|
||||
selector: S::Selector,
|
||||
usage: S::Usage,
|
||||
) -> Result<(&'a T, Drain<PendingTransition<S>>), S::Usage> {
|
||||
let item = &storage[id];
|
||||
self.change_replace(id, item.borrow(), selector, usage)
|
||||
.map(|drain| (item, drain))
|
||||
.map_err(|pending| pending.usage.start)
|
||||
}
|
||||
}
|
||||
|
||||
pub type BufferState = Unit<BufferUsage>;
|
||||
|
||||
impl Default for BufferState {
|
||||
fn default() -> Self {
|
||||
BufferState {
|
||||
init: BufferUsage::empty(),
|
||||
last: BufferUsage::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceState for BufferState {
|
||||
type Id = BufferId;
|
||||
type Selector = ();
|
||||
type Usage = BufferUsage;
|
||||
|
||||
fn query(
|
||||
&self,
|
||||
_selector: Self::Selector,
|
||||
) -> Option<Self::Usage> {
|
||||
Some(self.last)
|
||||
}
|
||||
|
||||
fn change(
|
||||
&mut self,
|
||||
id: Self::Id,
|
||||
_selector: Self::Selector,
|
||||
usage: Self::Usage,
|
||||
output: Option<&mut Vec<PendingTransition<Self>>>,
|
||||
) -> Result<(), PendingTransition<Self>> {
|
||||
let old = self.last;
|
||||
if usage != old {
|
||||
let pending = PendingTransition {
|
||||
id,
|
||||
selector: (),
|
||||
usage: old .. usage,
|
||||
};
|
||||
self.last = match output {
|
||||
Some(transitions) => {
|
||||
transitions.push(pending);
|
||||
usage
|
||||
}
|
||||
None => {
|
||||
if !old.is_empty() && BufferUsage::WRITE_ALL.intersects(old | usage) {
|
||||
return Err(pending);
|
||||
}
|
||||
old | usage
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn merge(
|
||||
&mut self,
|
||||
id: Self::Id,
|
||||
other: &Self,
|
||||
stitch: Stitch,
|
||||
output: Option<&mut Vec<PendingTransition<Self>>>,
|
||||
) -> Result<(), PendingTransition<Self>> {
|
||||
let usage = other.select(stitch);
|
||||
self.change(id, (), usage, output)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RangedStates<I, T> {
|
||||
ranges: Vec<(Range<I>, T)>,
|
||||
}
|
||||
|
||||
impl<I, T> Default for RangedStates<I, T> {
|
||||
fn default() -> Self {
|
||||
RangedStates {
|
||||
ranges: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Copy + PartialOrd, T: Copy> RangedStates<I, T> {
|
||||
fn isolate(&mut self, index: &Range<I>, default: T) -> &mut [(Range<I>, T)] {
|
||||
let start_pos = match self.ranges
|
||||
.iter()
|
||||
.position(|pair| pair.0.end > index.start)
|
||||
{
|
||||
Some(pos) => pos,
|
||||
None => {
|
||||
let pos = self.ranges.len();
|
||||
self.ranges.push((index.clone(), default));
|
||||
return &mut self.ranges[pos ..];
|
||||
}
|
||||
};
|
||||
|
||||
let mut pos = start_pos;
|
||||
let mut range_pos = index.start;
|
||||
loop {
|
||||
let (range, unit) = self.ranges[pos].clone();
|
||||
if range.start >= index.end {
|
||||
self.ranges.insert(pos, (range_pos .. index.end, default));
|
||||
pos += 1;
|
||||
break;
|
||||
}
|
||||
if range.start > range_pos {
|
||||
self.ranges.insert(pos, (range_pos .. range.start, default));
|
||||
pos += 1;
|
||||
range_pos = range.start;
|
||||
}
|
||||
if range.end >= index.end {
|
||||
self.ranges[pos].0.start = index.end;
|
||||
self.ranges.insert(pos, (range_pos .. index.end, unit));
|
||||
pos += 1;
|
||||
break;
|
||||
}
|
||||
pos += 1;
|
||||
range_pos = range.end;
|
||||
if pos == self.ranges.len() {
|
||||
self.ranges.push((range_pos .. index.end, default));
|
||||
pos += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
&mut self.ranges[start_pos .. pos]
|
||||
}
|
||||
}
|
||||
|
||||
type PlaneStates<T> = RangedStates<hal::image::Layer, T>;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct DepthStencilState {
|
||||
depth: Unit<TextureUsage>,
|
||||
stencil: Unit<TextureUsage>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
struct TextureStates {
|
||||
color_mips: ArrayVec<[PlaneStates<Unit<TextureUsage>>; MAX_MIP_LEVELS]>,
|
||||
depth_stencil: PlaneStates<DepthStencilState>,
|
||||
}
|
||||
|
||||
impl ResourceState for TextureStates {
|
||||
type Id = TextureId;
|
||||
type Selector = hal::image::SubresourceRange;
|
||||
type Usage = TextureUsage;
|
||||
|
||||
fn query(
|
||||
&self,
|
||||
selector: Self::Selector,
|
||||
) -> Option<Self::Usage> {
|
||||
let mut usage = None;
|
||||
if selector.aspects.contains(hal::format::Aspects::COLOR) {
|
||||
let num_levels = self.color_mips.len();
|
||||
let layer_start = num_levels.min(selector.levels.start as usize);
|
||||
let layer_end = num_levels.min(selector.levels.end as usize);
|
||||
for layer in self.color_mips[layer_start .. layer_end].iter() {
|
||||
for &(ref range, ref unit) in layer.ranges.iter() {
|
||||
if range.end > selector.layers.start && range.start < selector.layers.end {
|
||||
let old = usage.replace(unit.last);
|
||||
if old.is_some() && old != usage {
|
||||
return None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if selector.aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) {
|
||||
for &(ref range, ref ds) in self.depth_stencil.ranges.iter() {
|
||||
if range.end > selector.layers.start && range.start < selector.layers.end {
|
||||
if selector.aspects.contains(hal::format::Aspects::DEPTH) {
|
||||
let old = usage.replace(ds.depth.last);
|
||||
if old.is_some() && old != usage {
|
||||
return None
|
||||
}
|
||||
}
|
||||
if selector.aspects.contains(hal::format::Aspects::STENCIL) {
|
||||
let old = usage.replace(ds.stencil.last);
|
||||
if old.is_some() && old != usage {
|
||||
return None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
usage
|
||||
}
|
||||
|
||||
fn change(
|
||||
&mut self,
|
||||
id: Self::Id,
|
||||
selector: Self::Selector,
|
||||
usage: Self::Usage,
|
||||
mut output: Option<&mut Vec<PendingTransition<Self>>>,
|
||||
) -> Result<(), PendingTransition<Self>> {
|
||||
if selector.aspects.contains(hal::format::Aspects::COLOR) {
|
||||
while self.color_mips.len() < selector.levels.end as usize {
|
||||
self.color_mips.push(PlaneStates::default());
|
||||
}
|
||||
for level in selector.levels.clone() {
|
||||
let layers = self
|
||||
.color_mips[level as usize]
|
||||
.isolate(&selector.layers, Unit::new(usage));
|
||||
for &mut (ref range, ref mut unit) in layers {
|
||||
let old = unit.last;
|
||||
if old == usage {
|
||||
continue
|
||||
}
|
||||
let pending = PendingTransition {
|
||||
id,
|
||||
selector: hal::image::SubresourceRange {
|
||||
aspects: hal::format::Aspects::COLOR,
|
||||
levels: level .. level + 1,
|
||||
layers: range.clone(),
|
||||
},
|
||||
usage: old .. usage,
|
||||
};
|
||||
unit.last = match output.as_mut() {
|
||||
Some(out) => {
|
||||
out.push(pending);
|
||||
usage
|
||||
}
|
||||
None => {
|
||||
if !old.is_empty() && TextureUsage::WRITE_ALL.intersects(old | usage) {
|
||||
return Err(pending);
|
||||
}
|
||||
old | usage
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
if selector.aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) {
|
||||
unimplemented!() //TODO
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn merge(
|
||||
&mut self,
|
||||
_id: Self::Id,
|
||||
_other: &Self,
|
||||
_stitch: Stitch,
|
||||
_output: Option<&mut Vec<PendingTransition<Self>>>,
|
||||
) -> Result<(), PendingTransition<Self>> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct TextureViewState;
|
||||
|
||||
impl ResourceState for TextureViewState {
|
||||
type Id = TextureViewId;
|
||||
type Selector = ();
|
||||
type Usage = ();
|
||||
|
||||
fn query(
|
||||
&self,
|
||||
_selector: Self::Selector,
|
||||
) -> Option<Self::Usage> {
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn change(
|
||||
&mut self,
|
||||
_id: Self::Id,
|
||||
_selector: Self::Selector,
|
||||
_usage: Self::Usage,
|
||||
_output: Option<&mut Vec<PendingTransition<Self>>>,
|
||||
) -> Result<(), PendingTransition<Self>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn merge(
|
||||
&mut self,
|
||||
_id: Self::Id,
|
||||
_other: &Self,
|
||||
_stitch: Stitch,
|
||||
_output: Option<&mut Vec<PendingTransition<Self>>>,
|
||||
) -> Result<(), PendingTransition<Self>> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user