BUG
This commit is contained in:
@ -56,7 +56,7 @@ fn block_io_get_inputs(fields: zyn::syn::Fields) -> zyn::TokenStream
|
||||
{
|
||||
let fields = fields.as_named().unwrap().named.clone();
|
||||
zyn::zyn!(
|
||||
fn get_inputs_mut(&mut self) -> Vec<&mut dyn oxydsp_flowgraph::io::AnonymousIn>
|
||||
fn get_inputs_mut(&mut self) -> Vec<&mut dyn oxydsp_flowgraph::io::edge::AnonymousIn>
|
||||
{
|
||||
let mut acc = vec![];
|
||||
use oxydsp_flowgraph::block::BlockInput;
|
||||
@ -67,7 +67,7 @@ fn block_io_get_inputs(fields: zyn::syn::Fields) -> zyn::TokenStream
|
||||
acc
|
||||
}
|
||||
|
||||
fn get_inputs(&self) -> Vec<&dyn oxydsp_flowgraph::io::AnonymousIn>
|
||||
fn get_inputs(&self) -> Vec<&dyn oxydsp_flowgraph::io::edge::AnonymousIn>
|
||||
{
|
||||
let mut acc = vec![];
|
||||
use oxydsp_flowgraph::block::BlockInput;
|
||||
@ -85,7 +85,7 @@ fn block_io_get_outputs(fields: zyn::syn::Fields) -> zyn::TokenStream
|
||||
{
|
||||
let fields = fields.as_named().unwrap().named.clone();
|
||||
zyn::zyn!(
|
||||
fn get_outputs_mut(&mut self) -> Vec<&mut dyn oxydsp_flowgraph::io::AnonymousOut>
|
||||
fn get_outputs_mut(&mut self) -> Vec<&mut dyn oxydsp_flowgraph::io::edge::AnonymousOut>
|
||||
{
|
||||
let mut acc = vec![];
|
||||
use oxydsp_flowgraph::block::BlockOutput;
|
||||
@ -96,7 +96,7 @@ fn block_io_get_outputs(fields: zyn::syn::Fields) -> zyn::TokenStream
|
||||
acc
|
||||
}
|
||||
|
||||
fn get_outputs(&self) -> Vec<&dyn oxydsp_flowgraph::io::AnonymousOut>
|
||||
fn get_outputs(&self) -> Vec<&dyn oxydsp_flowgraph::io::edge::AnonymousOut>
|
||||
{
|
||||
let mut acc = vec![];
|
||||
use oxydsp_flowgraph::block::BlockOutput;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::io::AnonymousIn;
|
||||
use crate::io::AnonymousOut;
|
||||
use crate::io::edge::AnonymousIn;
|
||||
use crate::io::edge::AnonymousOut;
|
||||
use crate::io::In;
|
||||
use crate::io::Out;
|
||||
use crate::io::edge::BlockIOIndex;
|
||||
|
||||
@ -5,7 +5,6 @@ use std::thread::JoinHandle;
|
||||
use crossbeam_deque::Steal;
|
||||
use crossbeam_deque::Worker;
|
||||
|
||||
use crate::block;
|
||||
use crate::block::GraphableBlock;
|
||||
use crate::io::edge::BlockIOIndex;
|
||||
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
use std::any::Any;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::stream::StreamConsumer;
|
||||
use crate::stream::StreamProducer;
|
||||
use crate::stream::{self};
|
||||
use crate::stream::StreamReader;
|
||||
use crate::stream::StreamWriter;
|
||||
use crate::tag::TagSlot;
|
||||
use crate::tag::Tagged;
|
||||
|
||||
pub mod edge;
|
||||
|
||||
use crate::io::edge::BlockIOIndex;
|
||||
use crate::io::edge::Edge;
|
||||
|
||||
/// Represents a input port for a block
|
||||
@ -34,111 +34,276 @@ pub struct Out<T>
|
||||
edge: Arc<Mutex<Edge>>,
|
||||
}
|
||||
|
||||
/// Trait to manipulate a block's input in a type agnostic/erased way
|
||||
pub trait AnonymousIn
|
||||
// Input Output interfaces
|
||||
|
||||
/// Output interface to write elements in a "push" fashion
|
||||
pub struct OutPush<'a, T>
|
||||
{
|
||||
/// Inform the input about the index of the blocks it's in, as well as its port index
|
||||
fn set_index(&self, index: BlockIOIndex);
|
||||
data_writer: ManuallyDrop<StreamWriter<'a, T>>,
|
||||
tag_writer: ManuallyDrop<StreamWriter<'a, TagSlot>>,
|
||||
|
||||
/// Returns None or the block index of the block, and the block port of the corresponding
|
||||
/// Out object
|
||||
fn get_producer_block(&self) -> Option<BlockIOIndex>;
|
||||
|
||||
/// Sets the internal stream object
|
||||
fn set_anonymous_stream(&mut self, consumer: AnonymousStreamConsumer);
|
||||
total_length: usize,
|
||||
written_data: usize,
|
||||
written_tags: usize,
|
||||
start_index: usize,
|
||||
}
|
||||
|
||||
/// Trait to manipulate a block's output in a type agnostic/erased way
|
||||
pub trait AnonymousOut
|
||||
impl<'a, T> OutPush<'a, T>
|
||||
{
|
||||
/// Inform the output about the index of the blocks it's in, as well as its port index
|
||||
fn set_index(&self, index: BlockIOIndex);
|
||||
pub fn len(&self) -> usize
|
||||
{
|
||||
let data_slices = self.data_writer.slices();
|
||||
// This gives better performance !
|
||||
// Probably because it prevents claiming the whole buffer at once
|
||||
// But this is hacky. It should probably be managed at a lower level
|
||||
// ((data_slices.0.len() + data_slices.1.len()) / 2) - self.written_data
|
||||
|
||||
/// Sets the internal stream object
|
||||
fn set_anonymous_stream(&mut self, producer: AnonymousStreamProducer);
|
||||
data_slices.0.len() + data_slices.1.len() - self.written_data
|
||||
}
|
||||
|
||||
/// Returns None or the block index of the block, and the block port of the corresponding
|
||||
/// In object
|
||||
fn get_consumer_block(&self) -> Option<BlockIOIndex>;
|
||||
pub fn is_empty(&self) -> bool
|
||||
{
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Creates the stream with the correct corresponding type, in a type erased way.
|
||||
pub fn push(&mut self, data: Tagged<T>) -> Result<(), Tagged<T>>
|
||||
{
|
||||
if self.written_data >= self.total_length
|
||||
{
|
||||
return Err(data);
|
||||
}
|
||||
|
||||
let data_slices = self.data_writer.slices_mut();
|
||||
let tag_slices = self.tag_writer.slices_mut();
|
||||
|
||||
// Write a data
|
||||
let data_ref = {
|
||||
if self.written_data < data_slices.0.len()
|
||||
{
|
||||
&mut data_slices.0[self.written_data]
|
||||
}
|
||||
else
|
||||
{
|
||||
&mut data_slices.1[self.written_data - data_slices.0.len()]
|
||||
}
|
||||
};
|
||||
// Index of the taken element within the stream.
|
||||
*data_ref = MaybeUninit::new(data.0);
|
||||
let element_index = self.start_index + self.written_data;
|
||||
self.written_data += 1;
|
||||
|
||||
// Check for corresponding tag
|
||||
let tag_ref = {
|
||||
if self.written_tags < tag_slices.0.len()
|
||||
{
|
||||
&mut tag_slices.0[self.written_tags]
|
||||
}
|
||||
else
|
||||
{
|
||||
&mut tag_slices.1[self.written_tags - tag_slices.0.len()]
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(tag) = data.1
|
||||
{
|
||||
*tag_ref = MaybeUninit::new(TagSlot {
|
||||
position: element_index,
|
||||
tag,
|
||||
});
|
||||
self.written_tags += 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for OutPush<'a, T>
|
||||
{
|
||||
fn drop(&mut self)
|
||||
{
|
||||
let data_writer =
|
||||
unsafe { ManuallyDrop::<StreamWriter<'a, T>>::take(&mut self.data_writer) };
|
||||
let tag_writer =
|
||||
unsafe { ManuallyDrop::<StreamWriter<'a, TagSlot>>::take(&mut self.tag_writer) };
|
||||
tag_writer.produce(self.written_tags);
|
||||
data_writer.produce(self.written_data);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InIter<'a, T>
|
||||
{
|
||||
data_reader: ManuallyDrop<StreamReader<'a, T>>,
|
||||
tag_reader: ManuallyDrop<StreamReader<'a, TagSlot>>,
|
||||
|
||||
total_length: usize,
|
||||
total_tag_length: usize,
|
||||
read_data: usize,
|
||||
read_tags: usize,
|
||||
start_index: usize,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for InIter<'a, T>
|
||||
{
|
||||
type Item = Tagged<T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
if self.read_data >= self.total_length
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let data_slices = self.data_reader.slices_mut();
|
||||
let tag_slices = self.tag_reader.slices_mut();
|
||||
|
||||
// Take a data
|
||||
// SAFETY:
|
||||
// All takable should contain a valid element: guarteed by the queue
|
||||
// We strictly monotonicly take all elements, in order, in the slices.
|
||||
// No two same indices should be taken.
|
||||
// We cound the number of taken elemnts and consume the correct amount from the queue
|
||||
let data = {
|
||||
if self.read_data < data_slices.0.len()
|
||||
{
|
||||
unsafe { data_slices.0[self.read_data].take() }
|
||||
}
|
||||
else
|
||||
{
|
||||
unsafe { data_slices.1[self.read_data - data_slices.0.len()].take() }
|
||||
}
|
||||
};
|
||||
// Index of the taken element within the stream.
|
||||
let element_index = self.start_index + self.read_data;
|
||||
self.read_data += 1;
|
||||
|
||||
// Check for corresponding tag
|
||||
let mut tag = None;
|
||||
if self.read_tags < self.total_tag_length
|
||||
{
|
||||
let tag_ref = {
|
||||
if self.read_tags < tag_slices.0.len()
|
||||
{
|
||||
&mut tag_slices.0[self.read_tags]
|
||||
}
|
||||
else
|
||||
{
|
||||
&mut tag_slices.1[self.read_tags - tag_slices.0.len()]
|
||||
}
|
||||
};
|
||||
|
||||
// SAFETY:
|
||||
// Same as before : strictly monotic access in the tag slices
|
||||
if unsafe { tag_ref.peek().position == element_index }
|
||||
{
|
||||
// The next tag in line is tagging the just-poped element.
|
||||
// We get it
|
||||
tag = Some(unsafe { tag_ref.take().tag });
|
||||
self.read_tags += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Some(Tagged::new(data, tag))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>)
|
||||
{
|
||||
let len =
|
||||
self.data_reader.slices().0.len() + self.data_reader.slices().1.len() - self.read_data;
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for InIter<'a, T>
|
||||
{
|
||||
fn drop(&mut self)
|
||||
{
|
||||
let data_reader =
|
||||
unsafe { ManuallyDrop::<StreamReader<'a, T>>::take(&mut self.data_reader) };
|
||||
let tag_reader =
|
||||
unsafe { ManuallyDrop::<StreamReader<'a, TagSlot>>::take(&mut self.tag_reader) };
|
||||
tag_reader.consume(self.read_tags);
|
||||
data_reader.consume(self.read_data);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> ExactSizeIterator for InIter<'a, T> {}
|
||||
|
||||
impl<T: 'static> In<T>
|
||||
{
|
||||
pub fn iter<'a>(&'a mut self) -> InIter<'a, T>
|
||||
{
|
||||
let first_index = self.stream.as_ref().unwrap().first_index();
|
||||
let data_reader = self.stream.as_mut().unwrap().read_takable();
|
||||
let total_length = data_reader.slices().0.len() + data_reader.slices().1.len();
|
||||
let tag_reader = self.tag_stream.as_mut().unwrap().read_takable();
|
||||
let total_tag_length = tag_reader.slices().0.len() + tag_reader.slices().1.len();
|
||||
|
||||
InIter {
|
||||
data_reader: ManuallyDrop::new(data_reader),
|
||||
tag_reader: ManuallyDrop::new(tag_reader),
|
||||
read_data: 0,
|
||||
read_tags: 0,
|
||||
total_length,
|
||||
total_tag_length,
|
||||
start_index: first_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Out<T>
|
||||
{
|
||||
pub fn write_push<'a>(&'a mut self) -> OutPush<'a, T>
|
||||
{
|
||||
let first_index = self.stream.as_ref().unwrap().first_index();
|
||||
let data_writer = self.stream.as_mut().unwrap().write();
|
||||
let total_length = data_writer.slices().0.len() + data_writer.slices().1.len();
|
||||
|
||||
let tag_writer = self.tag_stream.as_mut().unwrap().write();
|
||||
|
||||
OutPush {
|
||||
data_writer: ManuallyDrop::new(data_writer),
|
||||
tag_writer: ManuallyDrop::new(tag_writer),
|
||||
total_length,
|
||||
written_data: 0,
|
||||
written_tags: 0,
|
||||
start_index: first_index,
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes an iterator to the output, sending the maximum amount of elements
|
||||
/// to the output.
|
||||
///
|
||||
/// This delegation of stream creation is necessary to allow the graph to manipulate
|
||||
/// it, as it cannot know about the generic type of the stream.
|
||||
fn create_anonymous_stream(
|
||||
&self,
|
||||
capacity: usize,
|
||||
) -> (AnonymousStreamProducer, AnonymousStreamConsumer);
|
||||
}
|
||||
|
||||
impl<T: 'static> AnonymousIn for In<T>
|
||||
{
|
||||
fn set_index(&self, index: BlockIOIndex)
|
||||
/// It will not consume the iterator more than what can be sent.
|
||||
///
|
||||
/// ```
|
||||
/// let writer = output.write();
|
||||
///
|
||||
/// // Send only 42s to the output
|
||||
/// writer.push_iter(std::iter::repeat(42));
|
||||
/// ```
|
||||
pub fn push_iter<I: Iterator<Item = Tagged<T>>>(&mut self, mut iter: I) -> bool
|
||||
{
|
||||
self.edge.lock().unwrap().to = Some(index);
|
||||
let mut pusher = self.write_push();
|
||||
let mut len = pusher.len();
|
||||
|
||||
while len > 0
|
||||
{
|
||||
len -= 1;
|
||||
match iter.next()
|
||||
{
|
||||
Some(element) => {let _ = pusher.push(element); },
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn get_producer_block(&self) -> Option<BlockIOIndex>
|
||||
/// Meta information
|
||||
/// Returns a string of the type of the output
|
||||
pub fn get_type_name(&self) -> &'static str
|
||||
{
|
||||
self.edge.lock().unwrap().from
|
||||
std::any::type_name::<T>()
|
||||
}
|
||||
|
||||
fn set_anonymous_stream(&mut self, consumer: AnonymousStreamConsumer)
|
||||
{
|
||||
let (stream, tag_stream) = consumer.downcast::<T>();
|
||||
self.stream = Some(stream);
|
||||
self.tag_stream = Some(tag_stream);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> AnonymousOut for Out<T>
|
||||
{
|
||||
fn set_index(&self, index: BlockIOIndex)
|
||||
{
|
||||
self.edge.lock().unwrap().from = Some(index);
|
||||
}
|
||||
|
||||
fn get_consumer_block(&self) -> Option<BlockIOIndex>
|
||||
{
|
||||
self.edge.lock().unwrap().to
|
||||
}
|
||||
|
||||
fn set_anonymous_stream(&mut self, producer: AnonymousStreamProducer)
|
||||
{
|
||||
let (stream, tag_stream) = producer.downcast::<T>();
|
||||
self.stream = Some(stream);
|
||||
self.tag_stream = Some(tag_stream);
|
||||
}
|
||||
|
||||
// Delegate stream creation to Out object
|
||||
// which knows the stream type
|
||||
fn create_anonymous_stream(
|
||||
&self,
|
||||
capacity: usize,
|
||||
) -> (AnonymousStreamProducer, AnonymousStreamConsumer)
|
||||
{
|
||||
let (tx, rx) = stream::bounded_queue::<T>(capacity);
|
||||
let (tx_tag, rx_tag) = stream::bounded_queue::<TagSlot>(capacity);
|
||||
((tx, tx_tag).into(), (rx, rx_tag).into())
|
||||
}
|
||||
}
|
||||
|
||||
/// A Reader to get data from an input
|
||||
pub struct InReader<'a, T>
|
||||
{
|
||||
data_slice_1: &'a mut [MaybeUninit<T>],
|
||||
data_slice_2: &'a mut [MaybeUninit<T>],
|
||||
// data_reader: StreamReader<'a, T>,
|
||||
// tag_reader: StreamReader<'a, TagSlot>,
|
||||
}
|
||||
|
||||
/// A writer to send data to an output
|
||||
pub struct OutWriter<'a, T>
|
||||
{
|
||||
data_slice_1: &'a mut [MaybeUninit<T>],
|
||||
data_slice_2: &'a mut [MaybeUninit<T>],
|
||||
// data_writer: StreamWriter<'a, T>,
|
||||
// tag_writer: StreamWriter<'a, TagSlot>,
|
||||
}
|
||||
|
||||
/// Creates a stream that can then be used to link blocks
|
||||
@ -168,207 +333,50 @@ pub fn stream<T>() -> (Out<T>, In<T>)
|
||||
)
|
||||
}
|
||||
|
||||
impl<T: 'static> In<T>
|
||||
pub fn streams<T, const N: usize>() -> ([Out<T>; N], [In<T>; N])
|
||||
{
|
||||
/// Gets a reader view from an input.
|
||||
///
|
||||
/// ```
|
||||
/// let reader = input.read();
|
||||
/// let data = reader.pop();
|
||||
/// ```
|
||||
pub fn read<'a>(&'a mut self) -> InReader
|
||||
{
|
||||
// let data_reader = self.stream.as_mut().unwrap().read();
|
||||
// let tag_reader = self.tag_stream.as_mut().unwrap().read();
|
||||
InReader {
|
||||
// data_reader,
|
||||
// tag_reader,
|
||||
}
|
||||
}
|
||||
// Ugly simultanous initialization
|
||||
let mut ins: [_; N] = std::array::from_fn(|_| None);
|
||||
let mut outs: [_; N] = std::array::from_fn(|_| None);
|
||||
|
||||
ins.iter_mut()
|
||||
.zip(outs.iter_mut())
|
||||
.for_each(|(input, output)| {
|
||||
let (newout, newin) = stream();
|
||||
*input = Some(newin);
|
||||
*output = Some(newout);
|
||||
});
|
||||
|
||||
let ins_some: [_; N] = std::array::from_fn(|i| ins[i].take().unwrap());
|
||||
let outs_some: [_; N] = std::array::from_fn(|i| outs[i].take().unwrap());
|
||||
|
||||
(outs_some, ins_some)
|
||||
}
|
||||
|
||||
impl<T: 'static> Out<T>
|
||||
{
|
||||
/// Gets a reader view from an output.
|
||||
///
|
||||
/// ```
|
||||
/// let writer = output.write();
|
||||
/// writer.push((data, tag).into());
|
||||
/// ```
|
||||
pub fn write<'a>(&'a mut self) -> OutWriter
|
||||
{
|
||||
OutWriter {
|
||||
// data_writer: self.stream.as_mut().unwrap().write(),
|
||||
// tag_writer: self.tag_stream.as_mut().unwrap().write(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes an iterator to the output, sending the maximum amount of elements
|
||||
/// to the output.
|
||||
///
|
||||
/// It will not consume the iterator more than what can be sent.
|
||||
///
|
||||
/// ```
|
||||
/// let writer = output.write();
|
||||
///
|
||||
/// // Send only 42s to the output
|
||||
/// writer.push_iter(std::iter::repeat(42));
|
||||
/// ```
|
||||
pub fn push_iter<I: Iterator<Item = Tagged<T>>>(&mut self, mut iter: I) -> bool
|
||||
{
|
||||
false
|
||||
// let writer = self.write();
|
||||
// let len = writer.len();
|
||||
//
|
||||
// for _ in 0..len
|
||||
// {
|
||||
// if let Some(elt) = iter.next()
|
||||
// {
|
||||
// let _ = writer.push(elt);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// true
|
||||
}
|
||||
|
||||
/// Meta information
|
||||
/// Returns a string of the type of the output
|
||||
pub fn get_type_name(&self) -> &'static str
|
||||
{
|
||||
std::any::type_name::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
// impl InReader
|
||||
// {
|
||||
// /// Gets the amount of elements that are available
|
||||
// /// on the input.
|
||||
// pub fn len(&self) -> usize
|
||||
// {
|
||||
// 0
|
||||
// //self.data_reader.len()
|
||||
// }
|
||||
//
|
||||
// /// Returns true iif no elements are available on the input.
|
||||
// pub fn is_empty(&self) -> bool
|
||||
// {
|
||||
// //self.len() == 0
|
||||
// true
|
||||
// }
|
||||
//
|
||||
// /// Pops an element from the input.
|
||||
// /// It is guaranteed to return `Some(data)` if
|
||||
// /// if pop was called strictly less times than len
|
||||
// pub fn pop(&self) -> Option<Tagged<T>>
|
||||
// {
|
||||
// None
|
||||
// // let data = self.data_reader.pop_with_index();
|
||||
// // if let Some((data, index)) = data
|
||||
// // {
|
||||
// // let mut tag = None;
|
||||
// // if self
|
||||
// // .tag_reader
|
||||
// // .peek(|t| t.position)
|
||||
// // .is_some_and(|x| x == index)
|
||||
// // {
|
||||
// // tag = self.tag_reader.pop();
|
||||
// // }
|
||||
// // Some((data, tag.map(|t| t.tag)).into())
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // None
|
||||
// // }
|
||||
// }
|
||||
//
|
||||
// /// Pops an element from the input, discarding the tag.
|
||||
// /// It is guaranteed to return `Some(data)` if
|
||||
// /// if pop was called strictly less times than len
|
||||
// pub fn pop_untag(&self) -> Option<T>
|
||||
// {
|
||||
// None
|
||||
// // self.pop().map(|data| data.into_inner())
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// impl<T> OutWriter<'_, T>
|
||||
// {
|
||||
// /// Gets how much room is available on the output
|
||||
// pub fn len(&self) -> usize
|
||||
// {
|
||||
// 0
|
||||
// //self.data_writer.len().min(self.tag_writer.len())
|
||||
// }
|
||||
//
|
||||
// /// Returns true iif no element can be sent
|
||||
// pub fn is_empty(&self) -> bool
|
||||
// {
|
||||
// true
|
||||
// //self.len() == 0
|
||||
// }
|
||||
//
|
||||
// /// Pushes some tagged data on the input.
|
||||
// ///
|
||||
// /// The operation succeeds (`Ok(())`) if there is enough room
|
||||
// /// Or fails returning the given data to the caller.
|
||||
// pub fn push(&self, data: Tagged<T>) -> Result<(), Tagged<T>>
|
||||
// {
|
||||
// Ok(())
|
||||
// // let (data, tag) = data.into();
|
||||
// // let position = self.data_writer.next_index();
|
||||
// // let tag = tag.map(|t| TagSlot { position, tag: t });
|
||||
// //
|
||||
// // match self.data_writer.push(data)
|
||||
// // {
|
||||
// // Ok(_) if tag.is_some() =>
|
||||
// // {
|
||||
// // let _ = self.tag_writer.push(tag.unwrap());
|
||||
// // Ok(())
|
||||
// // }
|
||||
// // Ok(_) => Ok(()),
|
||||
// // Err(data) => Err((data, tag.map(|t| t.tag)).into()),
|
||||
// // }
|
||||
// }
|
||||
//
|
||||
// /// Pushes some data on the input (not tagged).
|
||||
// ///
|
||||
// /// The operation succeeds (`Ok(())`) if there is enough room
|
||||
// /// Or fails returning the given data to the caller.
|
||||
// pub fn push_no_tag(&self, data: T) -> Result<(), T>
|
||||
// {
|
||||
// Ok(())
|
||||
// //self.data_writer.push(data)
|
||||
// }
|
||||
// }
|
||||
|
||||
// --------------------
|
||||
// Iterator facilites
|
||||
// --------------------
|
||||
|
||||
/// An iterator type to push data to output(s)
|
||||
pub struct PopIter<T>
|
||||
{
|
||||
len: usize,
|
||||
popped: usize,
|
||||
reader: T,
|
||||
}
|
||||
// An iterator type to push data to output(s)
|
||||
// pub struct PopIter<T>
|
||||
// {
|
||||
// len: usize,
|
||||
// popped: usize,
|
||||
// reader: T,
|
||||
// }
|
||||
|
||||
/// Type on which data can be popped from
|
||||
pub trait PopIterable<'a>
|
||||
{
|
||||
type Output;
|
||||
|
||||
/// Returns an iterator on the input elements :
|
||||
///
|
||||
/// ```
|
||||
/// (&mut input_a, &mut input_b, &mut input_c).pop_iter().for_each(|(a, b, c)| println!("Got {a}, {b} and {c} !"));
|
||||
/// ```
|
||||
fn pop_iter(&'a mut self) -> PopIter<Self::Output>;
|
||||
}
|
||||
// Type on which data can be popped from
|
||||
// pub trait PopIterable<'a>
|
||||
// {
|
||||
// type Output;
|
||||
//
|
||||
// /// Returns an iterator on the input elements :
|
||||
// ///
|
||||
// /// ```
|
||||
// /// (&mut input_a, &mut input_b, &mut input_c).pop_iter().for_each(|(a, b, c)| println!("Got {a}, {b} and {c} !"));
|
||||
// /// ```
|
||||
// fn pop_iter(&'a mut self) -> PopIter<Self::Output>;
|
||||
// }
|
||||
|
||||
// impl<'a, T: 'static> PopIterable<'a> for In<T>
|
||||
// {
|
||||
@ -419,69 +427,3 @@ pub trait PopIterable<'a>
|
||||
// impl_iterator_for_pop_iter_tuple! {10}
|
||||
// impl_iterator_for_pop_iter_tuple! {11}
|
||||
// impl_iterator_for_pop_iter_tuple! {12}
|
||||
|
||||
/// StreamProducer object for data and tags stored in a type
|
||||
/// agnostic/erased way.
|
||||
///
|
||||
/// This is needed for the graph system to manipulate and pass arround these objects
|
||||
/// as they can't/don't know about the generic types of the stream objects
|
||||
pub struct AnonymousStreamProducer
|
||||
{
|
||||
inner: Box<dyn Any>,
|
||||
inner_tag: StreamProducer<TagSlot>,
|
||||
}
|
||||
|
||||
/// StreamConsumer object for data and tags stored in a type
|
||||
/// agnostic/erased way.
|
||||
///
|
||||
/// This is needed for the graph system to manipulate and pass arround these objects
|
||||
/// as they can't/don't know about the generic types of the stream objects
|
||||
pub struct AnonymousStreamConsumer
|
||||
{
|
||||
inner: Box<dyn Any>,
|
||||
inner_tag: StreamConsumer<TagSlot>,
|
||||
}
|
||||
|
||||
impl<T: 'static> From<(StreamProducer<T>, StreamProducer<TagSlot>)> for AnonymousStreamProducer
|
||||
{
|
||||
fn from(value: (StreamProducer<T>, StreamProducer<TagSlot>)) -> Self
|
||||
{
|
||||
AnonymousStreamProducer {
|
||||
inner: Box::new(value.0),
|
||||
inner_tag: value.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> From<(StreamConsumer<T>, StreamConsumer<TagSlot>)> for AnonymousStreamConsumer
|
||||
{
|
||||
fn from(value: (StreamConsumer<T>, StreamConsumer<TagSlot>)) -> Self
|
||||
{
|
||||
AnonymousStreamConsumer {
|
||||
inner: Box::new(value.0),
|
||||
inner_tag: value.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AnonymousStreamProducer
|
||||
{
|
||||
pub(crate) fn downcast<T: 'static>(self) -> (StreamProducer<T>, StreamProducer<TagSlot>)
|
||||
{
|
||||
(
|
||||
*self.inner.downcast::<StreamProducer<T>>().unwrap(),
|
||||
self.inner_tag,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl AnonymousStreamConsumer
|
||||
{
|
||||
pub(crate) fn downcast<T: 'static>(self) -> (StreamConsumer<T>, StreamConsumer<TagSlot>)
|
||||
{
|
||||
(
|
||||
*self.inner.downcast::<StreamConsumer<T>>().unwrap(),
|
||||
self.inner_tag,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
use std::any::Any;
|
||||
|
||||
use crate::{io::{In, Out}, stream::{self, StreamConsumer, StreamProducer}, tag::TagSlot};
|
||||
|
||||
/// Shared object between a block's input and output objects
|
||||
/// so they can "communicate" and know about each other
|
||||
#[derive(Default)]
|
||||
@ -21,3 +25,158 @@ pub struct BlockIOIndex
|
||||
pub block_index: usize,
|
||||
pub port_index: usize,
|
||||
}
|
||||
|
||||
/// Trait to manipulate a block's input in a type agnostic/erased way
|
||||
pub trait AnonymousIn
|
||||
{
|
||||
/// Inform the input about the index of the blocks it's in, as well as its port index
|
||||
fn set_index(&self, index: BlockIOIndex);
|
||||
|
||||
/// Returns None or the block index of the block, and the block port of the corresponding
|
||||
/// Out object
|
||||
fn get_producer_block(&self) -> Option<BlockIOIndex>;
|
||||
|
||||
/// Sets the internal stream object
|
||||
fn set_anonymous_stream(&mut self, consumer: AnonymousStreamConsumer);
|
||||
}
|
||||
|
||||
/// Trait to manipulate a block's output in a type agnostic/erased way
|
||||
pub trait AnonymousOut
|
||||
{
|
||||
/// Inform the output about the index of the blocks it's in, as well as its port index
|
||||
fn set_index(&self, index: BlockIOIndex);
|
||||
|
||||
/// Sets the internal stream object
|
||||
fn set_anonymous_stream(&mut self, producer: AnonymousStreamProducer);
|
||||
|
||||
/// Returns None or the block index of the block, and the block port of the corresponding
|
||||
/// In object
|
||||
fn get_consumer_block(&self) -> Option<BlockIOIndex>;
|
||||
|
||||
/// Creates the stream with the correct corresponding type, in a type erased way.
|
||||
///
|
||||
/// This delegation of stream creation is necessary to allow the graph to manipulate
|
||||
/// it, as it cannot know about the generic type of the stream.
|
||||
fn create_anonymous_stream(
|
||||
&self,
|
||||
capacity: usize,
|
||||
) -> (AnonymousStreamProducer, AnonymousStreamConsumer);
|
||||
}
|
||||
|
||||
impl<T: 'static> AnonymousIn for In<T>
|
||||
{
|
||||
fn set_index(&self, index: BlockIOIndex)
|
||||
{
|
||||
self.edge.lock().unwrap().to = Some(index);
|
||||
}
|
||||
|
||||
fn get_producer_block(&self) -> Option<BlockIOIndex>
|
||||
{
|
||||
self.edge.lock().unwrap().from
|
||||
}
|
||||
|
||||
fn set_anonymous_stream(&mut self, consumer: AnonymousStreamConsumer)
|
||||
{
|
||||
let (stream, tag_stream) = consumer.downcast::<T>();
|
||||
self.stream = Some(stream);
|
||||
self.tag_stream = Some(tag_stream);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> AnonymousOut for Out<T>
|
||||
{
|
||||
fn set_index(&self, index: BlockIOIndex)
|
||||
{
|
||||
self.edge.lock().unwrap().from = Some(index);
|
||||
}
|
||||
|
||||
fn get_consumer_block(&self) -> Option<BlockIOIndex>
|
||||
{
|
||||
self.edge.lock().unwrap().to
|
||||
}
|
||||
|
||||
fn set_anonymous_stream(&mut self, producer: AnonymousStreamProducer)
|
||||
{
|
||||
let (stream, tag_stream) = producer.downcast::<T>();
|
||||
self.stream = Some(stream);
|
||||
self.tag_stream = Some(tag_stream);
|
||||
}
|
||||
|
||||
// Delegate stream creation to Out object
|
||||
// which knows the stream type
|
||||
fn create_anonymous_stream(
|
||||
&self,
|
||||
capacity: usize,
|
||||
) -> (AnonymousStreamProducer, AnonymousStreamConsumer)
|
||||
{
|
||||
let (tx, rx) = stream::bounded_queue::<T>(capacity);
|
||||
let (tx_tag, rx_tag) = stream::bounded_queue::<TagSlot>(capacity);
|
||||
((tx, tx_tag).into(), (rx, rx_tag).into())
|
||||
}
|
||||
}
|
||||
|
||||
/// StreamProducer object for data and tags stored in a type
|
||||
/// agnostic/erased way.
|
||||
///
|
||||
/// This is needed for the graph system to manipulate and pass arround these objects
|
||||
/// as they can't/don't know about the generic types of the stream objects
|
||||
pub struct AnonymousStreamProducer
|
||||
{
|
||||
inner: Box<dyn Any>,
|
||||
inner_tag: StreamProducer<TagSlot>,
|
||||
}
|
||||
|
||||
/// StreamConsumer object for data and tags stored in a type
|
||||
/// agnostic/erased way.
|
||||
///
|
||||
/// This is needed for the graph system to manipulate and pass arround these objects
|
||||
/// as they can't/don't know about the generic types of the stream objects
|
||||
pub struct AnonymousStreamConsumer
|
||||
{
|
||||
inner: Box<dyn Any>,
|
||||
inner_tag: StreamConsumer<TagSlot>,
|
||||
}
|
||||
|
||||
impl<T: 'static> From<(StreamProducer<T>, StreamProducer<TagSlot>)> for AnonymousStreamProducer
|
||||
{
|
||||
fn from(value: (StreamProducer<T>, StreamProducer<TagSlot>)) -> Self
|
||||
{
|
||||
AnonymousStreamProducer {
|
||||
inner: Box::new(value.0),
|
||||
inner_tag: value.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> From<(StreamConsumer<T>, StreamConsumer<TagSlot>)> for AnonymousStreamConsumer
|
||||
{
|
||||
fn from(value: (StreamConsumer<T>, StreamConsumer<TagSlot>)) -> Self
|
||||
{
|
||||
AnonymousStreamConsumer {
|
||||
inner: Box::new(value.0),
|
||||
inner_tag: value.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AnonymousStreamProducer
|
||||
{
|
||||
pub(crate) fn downcast<T: 'static>(self) -> (StreamProducer<T>, StreamProducer<TagSlot>)
|
||||
{
|
||||
(
|
||||
*self.inner.downcast::<StreamProducer<T>>().unwrap(),
|
||||
self.inner_tag,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl AnonymousStreamConsumer
|
||||
{
|
||||
pub(crate) fn downcast<T: 'static>(self) -> (StreamConsumer<T>, StreamConsumer<TagSlot>)
|
||||
{
|
||||
(
|
||||
*self.inner.downcast::<StreamConsumer<T>>().unwrap(),
|
||||
self.inner_tag,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,6 +52,36 @@ unsafe impl<T: Send> Sync for StreamProducer<T> {}
|
||||
unsafe impl<T: Send> Send for StreamConsumer<T> {}
|
||||
unsafe impl<T: Send> Sync for StreamConsumer<T> {}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct Takable<T>(MaybeUninit<T>);
|
||||
|
||||
impl<T> Takable<T>
|
||||
{
|
||||
pub fn new(element: T) -> Self
|
||||
{
|
||||
Takable(MaybeUninit::new(element))
|
||||
}
|
||||
|
||||
pub unsafe fn take(&mut self) -> T
|
||||
{
|
||||
unsafe { std::mem::replace(&mut self.0, MaybeUninit::uninit()).assume_init() }
|
||||
}
|
||||
|
||||
pub unsafe fn peek(&self) -> &T
|
||||
{
|
||||
unsafe { self.0.assume_init_ref() }
|
||||
}
|
||||
|
||||
pub unsafe fn peek_mut(&mut self) -> &mut T
|
||||
{
|
||||
unsafe { self.0.assume_init_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn takable_slice_from_maybe_uninitt<T>(slice: &mut [MaybeUninit<T>]) -> &mut [Takable<T>]
|
||||
{
|
||||
unsafe { std::mem::transmute(slice) }
|
||||
}
|
||||
|
||||
pub fn bounded_queue<T>(capacity: usize) -> (StreamProducer<T>, StreamConsumer<T>)
|
||||
{
|
||||
@ -89,8 +119,65 @@ pub fn bounded_queue<T>(capacity: usize) -> (StreamProducer<T>, StreamConsumer<T
|
||||
)
|
||||
}
|
||||
|
||||
pub struct StreamReader<'a, T>
|
||||
{
|
||||
slices: (&'a mut [Takable<T>], &'a mut [Takable<T>]),
|
||||
|
||||
// UNSAFE !
|
||||
consumer: &'a mut StreamConsumer<T>,
|
||||
}
|
||||
|
||||
pub struct StreamWriter<'a, T>
|
||||
{
|
||||
slices: (&'a mut [MaybeUninit<T>], &'a mut [MaybeUninit<T>]),
|
||||
|
||||
// UNSAFE !
|
||||
producer: &'a mut StreamProducer<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> StreamReader<'a, T>
|
||||
{
|
||||
pub fn slices(&self) -> (&[Takable<T>], &[Takable<T>])
|
||||
{
|
||||
(self.slices.0, self.slices.1)
|
||||
}
|
||||
|
||||
pub fn slices_mut(&mut self) -> (&mut [Takable<T>], &mut [Takable<T>])
|
||||
{
|
||||
(self.slices.0, self.slices.1)
|
||||
}
|
||||
|
||||
pub fn consume(self, amount: usize)
|
||||
{
|
||||
self.consumer.consume(amount);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> StreamWriter<'a, T>
|
||||
{
|
||||
pub fn slices(&self) -> (&[MaybeUninit<T>], &[MaybeUninit<T>])
|
||||
{
|
||||
(self.slices.0, self.slices.1)
|
||||
}
|
||||
|
||||
pub fn slices_mut(&mut self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>])
|
||||
{
|
||||
(self.slices.0, self.slices.1)
|
||||
}
|
||||
|
||||
pub fn produce(self, amount: usize)
|
||||
{
|
||||
self.producer.produce(amount);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> StreamProducer<T>
|
||||
{
|
||||
pub fn first_index(&self) -> usize
|
||||
{
|
||||
self.inner.head.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn produce(&mut self, written: usize)
|
||||
{
|
||||
// Advance head.
|
||||
@ -101,12 +188,10 @@ impl<T> StreamProducer<T>
|
||||
assert!(head + written - tail <= (self.inner.capacity_mask + 1));
|
||||
|
||||
// We want writes to the buffer to be visible when acquired in the pop side
|
||||
self.inner
|
||||
.head
|
||||
.store(head + written, Ordering::Release);
|
||||
self.inner.head.store(head + written, Ordering::Release);
|
||||
}
|
||||
|
||||
pub fn write(&mut self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>])
|
||||
pub fn write<'a>(&'a mut self) -> StreamWriter<'a, T>
|
||||
{
|
||||
// We need to claim the maximum amount of elements.
|
||||
let tail = self.inner.tail.load(Ordering::Acquire);
|
||||
@ -139,18 +224,18 @@ impl<T> StreamProducer<T>
|
||||
let k = &mut *self.inner.buffer.get();
|
||||
|
||||
let (start_to_head, head_to_end) = k.split_at_mut_unchecked(wrapped_head);
|
||||
let (start_to_tail, _tail_to_head) =
|
||||
start_to_head.split_at_mut_unchecked(wrapped_tail);
|
||||
|
||||
// This functions borrows the stream mutably. As such, only one instance
|
||||
// of these slices can exist for a given stream.
|
||||
(head_to_end, start_to_tail)
|
||||
StreamWriter {
|
||||
slices: (start_to_head, head_to_end),
|
||||
producer: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We MUST have : tail < head
|
||||
|
||||
if wrapped_tail < wrapped_head
|
||||
{
|
||||
// Current configuration :
|
||||
@ -158,7 +243,7 @@ impl<T> StreamProducer<T>
|
||||
// | |
|
||||
// tail head
|
||||
// ___ ____
|
||||
// slice1 slice2
|
||||
// slice2 slice1
|
||||
|
||||
// SAFETY:
|
||||
//
|
||||
@ -175,7 +260,10 @@ impl<T> StreamProducer<T>
|
||||
let (start_to_tail, _tail_to_head) =
|
||||
start_to_head.split_at_mut_unchecked(wrapped_tail);
|
||||
|
||||
(head_to_end, start_to_tail)
|
||||
StreamWriter {
|
||||
slices: (head_to_end, start_to_tail),
|
||||
producer: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -203,10 +291,14 @@ impl<T> StreamProducer<T>
|
||||
// Head and tail are both indices of the slice
|
||||
unsafe {
|
||||
let k = &mut *self.inner.buffer.get();
|
||||
let (_start_to_head, head_to_tail) = k.split_at_mut_unchecked(wrapped_head);
|
||||
let (head_to_tail, empty_slice) =
|
||||
head_to_tail.split_at_mut_unchecked(wrapped_tail - wrapped_head);
|
||||
(head_to_tail, empty_slice)
|
||||
let (start_to_tail, _tail_to_end) = k.split_at_mut_unchecked(wrapped_tail);
|
||||
let (_start_to_head, head_to_tail) = start_to_tail.split_at_mut_unchecked(wrapped_head);
|
||||
let (empty_slice, head_to_tail) = head_to_tail.split_at_mut_unchecked(0);
|
||||
|
||||
StreamWriter {
|
||||
slices: (head_to_tail, empty_slice),
|
||||
producer: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,15 +314,18 @@ impl<T> StreamConsumer<T>
|
||||
let tail = self.inner.tail.load(Ordering::Relaxed);
|
||||
|
||||
// Check bounds
|
||||
assert!(tail + read <= head);
|
||||
assert!(tail + read <= head);
|
||||
|
||||
// We want writes to the buffer to be visible when acquired in the pop side
|
||||
self.inner
|
||||
.tail
|
||||
.store(tail + read, Ordering::Release);
|
||||
self.inner.tail.store(tail + read, Ordering::Release);
|
||||
}
|
||||
|
||||
pub fn read_uninit(&mut self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>])
|
||||
pub fn first_index(&self) -> usize
|
||||
{
|
||||
self.inner.tail.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn read_takable<'a>(&'a mut self) -> StreamReader<'a, T>
|
||||
{
|
||||
// We need to claim the maximum amount of elements.
|
||||
let head = self.inner.head.load(Ordering::Acquire);
|
||||
@ -247,14 +342,20 @@ impl<T> StreamConsumer<T>
|
||||
// Buffer is empty. Return empty slice
|
||||
unsafe {
|
||||
let k = &mut *self.inner.buffer.get();
|
||||
let head_to_tail = &mut k[wrapped_head..wrapped_tail];
|
||||
let (empty_1, empty_2) = head_to_tail.split_at_mut_unchecked(0);
|
||||
(empty_1, empty_2)
|
||||
let empty = &mut k[0..0];
|
||||
let (empty_1, empty_2) = empty.split_at_mut_unchecked(0);
|
||||
StreamReader {
|
||||
slices: (
|
||||
takable_slice_from_maybe_uninitt(empty_1),
|
||||
takable_slice_from_maybe_uninitt(empty_2),
|
||||
),
|
||||
consumer: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Necessarly: wrapped_tail < wrapped_head
|
||||
// Necessarly: wrapped_tail <= wrapped_head
|
||||
// Two cases : The buffer overlaps the wrapping or not
|
||||
if wrapped_tail < wrapped_head
|
||||
{
|
||||
@ -275,7 +376,15 @@ impl<T> StreamConsumer<T>
|
||||
let k = &mut (&mut *self.inner.buffer.get())[wrapped_tail..wrapped_head];
|
||||
let (tail_to_head, empty_slice) =
|
||||
k.split_at_mut_unchecked(wrapped_head - wrapped_tail);
|
||||
(tail_to_head, empty_slice)
|
||||
assert_eq!(empty_slice.len(), 0);
|
||||
|
||||
StreamReader {
|
||||
slices: (
|
||||
takable_slice_from_maybe_uninitt(tail_to_head),
|
||||
takable_slice_from_maybe_uninitt(empty_slice),
|
||||
),
|
||||
consumer: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -310,112 +419,31 @@ impl<T> StreamConsumer<T>
|
||||
let (start_to_head, _head_to_tail) =
|
||||
start_to_tail.split_at_mut_unchecked(wrapped_head);
|
||||
|
||||
(tail_to_end, start_to_head)
|
||||
StreamReader {
|
||||
slices: (
|
||||
takable_slice_from_maybe_uninitt(tail_to_end),
|
||||
takable_slice_from_maybe_uninitt(start_to_head),
|
||||
),
|
||||
consumer: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a reader of contiguous elements that
|
||||
// satisfy the predicate
|
||||
// pub fn read_while<F>(&mut self, predicate: F) -> StreamReader<'_, T>
|
||||
// where
|
||||
// F: Fn(&T) -> bool,
|
||||
// {
|
||||
// // Take a normal reader. This contains available elements to read.
|
||||
// let mut reader = self.read();
|
||||
//
|
||||
// // We need to trim the slices to keep only the satified elements
|
||||
//
|
||||
// // First slice
|
||||
// let mut first_kept = 0;
|
||||
// // SAFETY:
|
||||
// //
|
||||
// // Only us can have a reference to these slices of the buffer
|
||||
// for element in unsafe { &*reader.first.get() }
|
||||
// {
|
||||
// // SAFETY
|
||||
// //
|
||||
// // If this element is in a reader returned by self.read
|
||||
// // with no pop called, we know it is initialized
|
||||
// let init_element = unsafe { element.assume_init_ref() };
|
||||
// let sat = predicate(init_element);
|
||||
// if !sat
|
||||
// {
|
||||
// // Stop here
|
||||
// // Forget about second slice
|
||||
// reader.second_len = 0;
|
||||
// reader.second = None;
|
||||
//
|
||||
// // Trim first slice
|
||||
// reader.first_len = first_kept;
|
||||
// unsafe {
|
||||
// reader.first = std::mem::transmute::<
|
||||
// &[MaybeUninit<T>],
|
||||
// &UnsafeCell<[MaybeUninit<T>]>,
|
||||
// >(&(&*reader.first.get())[0..first_kept]);
|
||||
// }
|
||||
//
|
||||
// return reader;
|
||||
// }
|
||||
// first_kept += 1;
|
||||
// }
|
||||
//
|
||||
// // If we are here, all of the elements of the first slice, satisfy the predicate
|
||||
//
|
||||
// if let Some(second_slice) = &mut reader.second
|
||||
// {
|
||||
// // Second slice
|
||||
// let mut second_kept = 0;
|
||||
// // SAFETY:
|
||||
// //
|
||||
// // Only us can have a reference to these slices of the buffer
|
||||
// for element in unsafe { &*second_slice.get() }
|
||||
// {
|
||||
// // SAFETY
|
||||
// //
|
||||
// // If this element is in a reader returned by self.read
|
||||
// // with no pop called, we know it is initialized
|
||||
// let init_element = unsafe { element.assume_init_ref() };
|
||||
// let sat = predicate(init_element);
|
||||
// if !sat
|
||||
// {
|
||||
// // Stop here
|
||||
// // Trim second slice
|
||||
// reader.second_len = second_kept;
|
||||
// unsafe {
|
||||
// reader.second = Some(std::mem::transmute::<
|
||||
// &[MaybeUninit<T>],
|
||||
// &UnsafeCell<[MaybeUninit<T>]>,
|
||||
// >(
|
||||
// &(&*second_slice.get())[0..first_kept]
|
||||
// ));
|
||||
// }
|
||||
// return reader;
|
||||
// }
|
||||
// second_kept += 1;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return reader;
|
||||
// }
|
||||
}
|
||||
|
||||
impl<T: Copy> StreamConsumer<T>
|
||||
{
|
||||
pub fn read(&mut self) -> (&[T], &[T])
|
||||
{
|
||||
let (slice_1, slice_2) = self.read_uninit();
|
||||
unsafe
|
||||
{
|
||||
(std::mem::transmute(slice_1), std::mem::transmute(slice_2))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// impl<T: Copy> StreamConsumer<T>
|
||||
// {
|
||||
// pub fn read(&mut self) -> (&[T], &[T])
|
||||
// {
|
||||
// let (slice_1, slice_2) = self.read_takable();
|
||||
// unsafe { (std::mem::transmute(slice_1), std::mem::transmute(slice_2)) }
|
||||
// }
|
||||
// }
|
||||
|
||||
mod test
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
@ -428,7 +456,8 @@ mod test
|
||||
let (mut tx, mut rx) = bounded_queue::<usize>(4);
|
||||
|
||||
{
|
||||
let (a, b) = tx.write();
|
||||
let mut writer = tx.write();
|
||||
let (a, b) = writer.slices_mut();
|
||||
assert_eq!(a.len(), 4);
|
||||
assert_eq!(b.len(), 0);
|
||||
|
||||
@ -441,24 +470,28 @@ mod test
|
||||
}
|
||||
|
||||
{
|
||||
let (a, b) = rx.read();
|
||||
let mut reader = rx.read_takable();
|
||||
let (a, b) = reader.slices_mut();
|
||||
assert_eq!(a.len(), 4);
|
||||
assert_eq!(b.len(), 0);
|
||||
|
||||
assert_eq!(a[0], 0);
|
||||
assert_eq!(a[1], 1);
|
||||
assert_eq!(a[2], 2);
|
||||
assert_eq!(a[3], 3);
|
||||
unsafe {
|
||||
assert_eq!(a[0].take(), 0);
|
||||
assert_eq!(a[1].take(), 1);
|
||||
assert_eq!(a[2].take(), 2);
|
||||
assert_eq!(a[3].take(), 3);
|
||||
}
|
||||
|
||||
rx.consume(4);
|
||||
}
|
||||
|
||||
// Put stream into weird situation
|
||||
{
|
||||
let (a, b) = tx.write();
|
||||
let mut writer = tx.write();
|
||||
let (a, b) = writer.slices_mut();
|
||||
assert_eq!(a.len(), 4);
|
||||
assert_eq!(b.len(), 0);
|
||||
|
||||
|
||||
a[0] = MaybeUninit::new(0);
|
||||
a[1] = MaybeUninit::new(1);
|
||||
a[2] = MaybeUninit::new(2);
|
||||
@ -467,27 +500,33 @@ mod test
|
||||
}
|
||||
|
||||
{
|
||||
let (a, b) = rx.read();
|
||||
let mut reader = rx.read_takable();
|
||||
let (a, b) = reader.slices_mut();
|
||||
assert_eq!(a.len(), 3);
|
||||
assert_eq!(b.len(), 0);
|
||||
|
||||
assert_eq!(a[0], 0);
|
||||
assert_eq!(a[1], 1);
|
||||
assert_eq!(a[2], 2);
|
||||
|
||||
unsafe
|
||||
{
|
||||
assert_eq!(a[0].take(), 0);
|
||||
assert_eq!(a[1].take(), 1);
|
||||
assert_eq!(a[2].take(), 2);
|
||||
}
|
||||
|
||||
rx.consume(1);
|
||||
}
|
||||
|
||||
{
|
||||
let (a, b) = tx.write();
|
||||
let writer = tx.write();
|
||||
let (a, b) = writer.slices();
|
||||
assert_eq!(a.len(), 1);
|
||||
assert_eq!(b.len(), 1);
|
||||
assert_eq!(b.len(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
let (a, b) = rx.read();
|
||||
let reader = rx.read_takable();
|
||||
let (a, b) = reader.slices();
|
||||
assert_eq!(a.len(), 2);
|
||||
assert_eq!(b.len(), 0);
|
||||
assert_eq!(b.len(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,7 +178,7 @@ impl Tag
|
||||
}
|
||||
|
||||
/// Creates a new tag, which is the combination of the given tags
|
||||
pub fn from_tags<const N: usize>(tag_opts: [&Tag; N]) -> Tag
|
||||
pub fn from_tags<const N: usize>(tag_opts: &[&Tag; N]) -> Tag
|
||||
{
|
||||
let new_tag = Self::default();
|
||||
{
|
||||
@ -197,7 +197,7 @@ impl Tag
|
||||
///
|
||||
/// If all the tag options are None, None is returned
|
||||
/// Otherwise it is Some of the combination of all of the tags which are Some
|
||||
pub fn from_tag_opts<const N: usize>(tag_opts: [&Option<Tag>; N]) -> Option<Tag>
|
||||
pub fn from_tag_opts<const N: usize>(tag_opts: &[&Option<Tag>; N]) -> Option<Tag>
|
||||
{
|
||||
if tag_opts.iter().all(|t| t.is_none())
|
||||
{
|
||||
@ -256,7 +256,7 @@ impl TagMergable<Tag> for Tag
|
||||
{
|
||||
fn merge(&self, other: &Self) -> Self
|
||||
{
|
||||
Self::from_tags([self, other])
|
||||
Self::from_tags(&[self, other])
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,7 +264,7 @@ impl TagMergable<Option<Tag>> for Option<Tag>
|
||||
{
|
||||
fn merge(&self, other: &Self) -> Self
|
||||
{
|
||||
Tag::from_tag_opts([self, other])
|
||||
Tag::from_tag_opts(&[self, other])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user