Add a miri test for the buffer management's safety
This commit is contained in:
parent
112c801bc4
commit
58174c1af0
|
@ -368,3 +368,133 @@ impl BufferManager {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(miri, test))]
|
||||||
|
mod miri {
|
||||||
|
use super::*;
|
||||||
|
use crate::prelude::{new_nonzero_u32, PortNames};
|
||||||
|
|
||||||
|
const BUFFER_SIZE: usize = 512;
|
||||||
|
const NUM_MAIN_INPUT_CHANNELS: usize = 1;
|
||||||
|
const NUM_MAIN_OUTPUT_CHANNELS: usize = 2;
|
||||||
|
|
||||||
|
const NUM_AUX_CHANNELS: usize = 2;
|
||||||
|
const NUM_AUX_PORTS: usize = 2;
|
||||||
|
|
||||||
|
const AUDIO_IO_LAYOUT: AudioIOLayout = AudioIOLayout {
|
||||||
|
main_input_channels: Some(new_nonzero_u32(NUM_MAIN_INPUT_CHANNELS as u32)),
|
||||||
|
main_output_channels: Some(new_nonzero_u32(NUM_MAIN_OUTPUT_CHANNELS as u32)),
|
||||||
|
aux_input_ports: &[new_nonzero_u32(NUM_AUX_CHANNELS as u32); NUM_AUX_PORTS],
|
||||||
|
aux_output_ports: &[new_nonzero_u32(NUM_AUX_CHANNELS as u32); NUM_AUX_PORTS],
|
||||||
|
names: PortNames::const_default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn buffer_io() {
|
||||||
|
// This works very similarly to the standalone CPAL and dummy backends
|
||||||
|
let mut main_io_storage = vec![vec![0.0f32; BUFFER_SIZE]; NUM_MAIN_OUTPUT_CHANNELS];
|
||||||
|
let mut aux_input_storage =
|
||||||
|
vec![vec![vec![0.0f32; BUFFER_SIZE]; NUM_AUX_CHANNELS]; NUM_AUX_PORTS];
|
||||||
|
let mut aux_output_storage =
|
||||||
|
vec![vec![vec![0.0f32; BUFFER_SIZE]; NUM_AUX_CHANNELS]; NUM_AUX_PORTS];
|
||||||
|
|
||||||
|
let mut main_io_channel_pointers: Vec<*mut f32> = main_io_storage
|
||||||
|
.iter_mut()
|
||||||
|
.map(|channel_slice| channel_slice.as_mut_ptr())
|
||||||
|
.collect();
|
||||||
|
let mut aux_input_channel_pointers: Vec<Vec<*mut f32>> = aux_input_storage
|
||||||
|
.iter_mut()
|
||||||
|
.map(|aux_input_storage| {
|
||||||
|
aux_input_storage
|
||||||
|
.iter_mut()
|
||||||
|
.map(|channel_slice| channel_slice.as_mut_ptr())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let mut aux_output_channel_pointers: Vec<Vec<*mut f32>> = aux_output_storage
|
||||||
|
.iter_mut()
|
||||||
|
.map(|aux_output_storage| {
|
||||||
|
aux_output_storage
|
||||||
|
.iter_mut()
|
||||||
|
.map(|channel_slice| channel_slice.as_mut_ptr())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// The actual buffer management here works the same as in the JACK backend. See that
|
||||||
|
// implementation for more information.
|
||||||
|
let mut buffer_manager = BufferManager::for_audio_io_layout(BUFFER_SIZE, AUDIO_IO_LAYOUT);
|
||||||
|
let buffers = unsafe {
|
||||||
|
buffer_manager.create_buffers(BUFFER_SIZE, |buffer_sources| {
|
||||||
|
*buffer_sources.main_output_channel_pointers = Some(ChannelPointers {
|
||||||
|
ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(),
|
||||||
|
num_channels: main_io_channel_pointers.len(),
|
||||||
|
});
|
||||||
|
*buffer_sources.main_input_channel_pointers = Some(ChannelPointers {
|
||||||
|
ptrs: NonNull::new(main_io_channel_pointers.as_mut_ptr()).unwrap(),
|
||||||
|
num_channels: NUM_MAIN_INPUT_CHANNELS.min(main_io_channel_pointers.len()),
|
||||||
|
});
|
||||||
|
|
||||||
|
for (input_source_channel_pointers, input_channel_pointers) in buffer_sources
|
||||||
|
.aux_input_channel_pointers
|
||||||
|
.iter_mut()
|
||||||
|
.zip(aux_input_channel_pointers.iter_mut())
|
||||||
|
{
|
||||||
|
*input_source_channel_pointers = Some(ChannelPointers {
|
||||||
|
ptrs: NonNull::new(input_channel_pointers.as_mut_ptr()).unwrap(),
|
||||||
|
num_channels: input_channel_pointers.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (output_source_channel_pointers, output_channel_pointers) in buffer_sources
|
||||||
|
.aux_output_channel_pointers
|
||||||
|
.iter_mut()
|
||||||
|
.zip(aux_output_channel_pointers.iter_mut())
|
||||||
|
{
|
||||||
|
*output_source_channel_pointers = Some(ChannelPointers {
|
||||||
|
ptrs: NonNull::new(output_channel_pointers.as_mut_ptr()).unwrap(),
|
||||||
|
num_channels: output_channel_pointers.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
for channel_samples in buffers
|
||||||
|
.main_buffer
|
||||||
|
.iter_samples()
|
||||||
|
.chain(
|
||||||
|
buffers
|
||||||
|
.aux_inputs
|
||||||
|
.iter_mut()
|
||||||
|
.flat_map(|buffer| buffer.iter_samples()),
|
||||||
|
)
|
||||||
|
.chain(
|
||||||
|
buffers
|
||||||
|
.aux_outputs
|
||||||
|
.iter_mut()
|
||||||
|
.flat_map(|buffer| buffer.iter_samples()),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for sample in channel_samples {
|
||||||
|
*sample += 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// These checks are fine due to stacked borrows even without explicitly dropping `buffers`.
|
||||||
|
// If we were to access `buffers` again after this miri would trigger an error.
|
||||||
|
for channel in main_io_storage
|
||||||
|
.iter()
|
||||||
|
.chain(aux_output_storage.iter().flat_map(|storage| storage.iter()))
|
||||||
|
{
|
||||||
|
for sample in channel {
|
||||||
|
assert!(*sample == 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for channel in aux_input_storage.iter().flat_map(|storage| storage.iter()) {
|
||||||
|
for sample in channel {
|
||||||
|
assert!(*sample == 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue