Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 92 additions & 18 deletions selene-core/rust/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub enum OutputStreamError {

pub trait StreamWritable {
const TYPE_REPR: u16;
fn write(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError> {
fn write<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError> {
stream
.write_all(&Self::TYPE_REPR.to_le_bytes())
.map_err(OutputStreamError::IoError)?;
Expand All @@ -32,7 +32,7 @@ pub trait StreamWritable {
self.write_impl(stream)
}
fn get_length(&self) -> Result<u16, OutputStreamError>;
fn write_impl(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError>;
fn write_impl<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError>;
}
impl StreamWritable for &str {
const TYPE_REPR: u16 = 3;
Expand All @@ -42,7 +42,7 @@ impl StreamWritable for &str {
}
Ok(self.len() as u16)
}
fn write_impl(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError> {
fn write_impl<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError> {
if self.contains('\0') {
return Err(OutputStreamError::CorruptedStringError(
self.as_bytes().into(),
Expand All @@ -55,7 +55,7 @@ impl StreamWritable for &str {
}
pub trait StreamWritableSingle {
const TYPE_REPR: u16;
fn write_impl(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError>;
fn write_impl<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError>;
}
impl<T: StreamWritableSingle> StreamWritable for T {
const TYPE_REPR: u16 = T::TYPE_REPR;
Expand All @@ -64,7 +64,7 @@ impl<T: StreamWritableSingle> StreamWritable for T {
// The encoding we use defines a length of 0 as a single non-array value.
Ok(0)
}
fn write_impl(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError> {
fn write_impl<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError> {
self.write_impl(stream)
}
}
Expand All @@ -79,7 +79,7 @@ impl<T: StreamWritableSingle> StreamWritable for &[T] {
}
Ok(self.len() as u16)
}
fn write_impl(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError> {
fn write_impl<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError> {
for item in self.iter() {
item.write_impl(stream)?;
}
Expand All @@ -88,7 +88,7 @@ impl<T: StreamWritableSingle> StreamWritable for &[T] {
}
impl StreamWritableSingle for bool {
const TYPE_REPR: u16 = 4;
fn write_impl(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError> {
fn write_impl<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError> {
let byte = if *self { 1u8 } else { 0u8 };
stream
.write_all(&[byte])
Expand All @@ -97,52 +97,126 @@ impl StreamWritableSingle for bool {
}
impl StreamWritableSingle for u64 {
const TYPE_REPR: u16 = 1;
fn write_impl(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError> {
fn write_impl<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError> {
stream
.write_all(&self.to_le_bytes())
.map_err(OutputStreamError::IoError)
}
}
impl StreamWritableSingle for i64 {
const TYPE_REPR: u16 = 5;
fn write_impl(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError> {
fn write_impl<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError> {
stream
.write_all(&self.to_le_bytes())
.map_err(OutputStreamError::IoError)
}
}
impl StreamWritableSingle for f64 {
const TYPE_REPR: u16 = 2;
fn write_impl(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError> {
fn write_impl<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError> {
stream
.write_all(&self.to_le_bytes())
.map_err(OutputStreamError::IoError)
}
}
impl StreamWritableSingle for u8 {
const TYPE_REPR: u16 = 9116;
fn write_impl(&self, stream: &mut dyn Write) -> Result<(), OutputStreamError> {
fn write_impl<W: Write>(&self, stream: &mut W) -> Result<(), OutputStreamError> {
stream
.write_all(&self.to_le_bytes())
.map_err(OutputStreamError::IoError)
}
}

pub struct InternalBuffer {
buffer: Vec<u8>,
last_read_index: usize,
}
impl Default for InternalBuffer {
fn default() -> Self {
InternalBuffer {
buffer: Vec::with_capacity(1024 * 64),
last_read_index: 0,
}
}
}
impl Write for InternalBuffer {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.buffer.extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl InternalBuffer {
fn try_read(&mut self, length: usize) -> Result<&[u8], OutputStreamError> {
let max_len = self.buffer.len() - self.last_read_index;
let length = length.min(max_len);
let data = &self.buffer[self.last_read_index..self.last_read_index + length];
self.last_read_index += length;
Ok(data)
}
}

pub enum OutputWriter {
Internal(InternalBuffer),
Stdout(std::io::Stdout),
Stderr(std::io::Stderr),
File(std::fs::File),
Tcp(std::net::TcpStream),
}
impl Write for OutputWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
match self {
OutputWriter::Internal(internal) => internal.write(buf),
OutputWriter::Stdout(stdout) => stdout.write(buf),
OutputWriter::Stderr(stderr) => stderr.write(buf),
OutputWriter::File(file) => file.write(buf),
OutputWriter::Tcp(tcp) => tcp.write(buf),
}
}
fn flush(&mut self) -> std::io::Result<()> {
match self {
OutputWriter::Internal(internal) => internal.flush(),
OutputWriter::Stdout(stdout) => stdout.flush(),
OutputWriter::Stderr(stderr) => stderr.flush(),
OutputWriter::File(file) => file.flush(),
OutputWriter::Tcp(tcp) => tcp.flush(),
}
}
}

pub struct OutputStream {
writer: Box<dyn Write>,
writer: OutputWriter,
bytes_written: usize,
}
impl OutputStream {
pub fn new(writer: Box<dyn Write>) -> Self {
OutputStream { writer }
pub fn new(writer: OutputWriter) -> Self {
OutputStream {
writer,
bytes_written: 0,
}
}
pub fn get_bytes_written(&self) -> usize {
self.bytes_written
}
fn write_impl(&mut self, value: &[u8]) -> Result<(), OutputStreamError> {
match self.writer.write_all(value) {
Ok(_) => Ok(()),
Err(e) => Err(OutputStreamError::IoError(e)),
}
self.writer
.write_all(value)
.map_err(OutputStreamError::IoError)
}
pub fn flush(&mut self) -> Result<(), OutputStreamError> {
self.writer.flush().map_err(OutputStreamError::IoError)
}
pub fn try_read(&mut self, length: usize) -> Result<&[u8], OutputStreamError> {
match &mut self.writer {
OutputWriter::Internal(internal) => internal.try_read(length),
_ => Err(OutputStreamError::OtherError(
"Read operations are not supported for external writers".to_string(),
)),
}
}

pub fn begin_message(&mut self, time_cursor: u64) -> Result<(), OutputStreamError> {
self.write_impl(&time_cursor.to_le_bytes())
Expand Down
2 changes: 1 addition & 1 deletion selene-core/rust/runtime/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ macro_rules! export_runtime_plugin {
pub unsafe extern "C" fn selene_runtime_shot_end(
instance: RuntimeInstance,
shot_id: u64,
seed: u64,
seed: u64, // TODO: this is unused and will be removed in the next API release
) -> i32 {
Helper::shot_end(instance)
}
Expand Down
2 changes: 1 addition & 1 deletion selene-core/rust/simulator/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ macro_rules! export_simulator_plugin {
#[unsafe(no_mangle)]
pub unsafe extern "C" fn selene_simulator_shot_end(
instance: SimulatorInstance,
seed: u64,
seed: u64, // TODO: this is unused and will be removed in the next API release
) -> i32 {
Helper::shot_end(instance)
}
Expand Down
2 changes: 1 addition & 1 deletion selene-ext/runtimes/soft_rz/rust/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ impl RuntimeInterface for SoftRZRuntime {
}
}
}
bail!("No measurement operation with result {result_id} found")
Ok(()) // If the measurement isn't in the queue, it has already been forced.
}
fn get_bool_result(&mut self, result_id: u64) -> Result<Option<bool>> {
if result_id >= self.future_results.len() as u64 {
Expand Down
20 changes: 20 additions & 0 deletions selene-sim/c/include/selene/selene.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ struct selene_void_result_t selene_dump_state(struct SeleneInstance *instance,

struct selene_void_result_t selene_exit(struct SeleneInstance *instance);

/**
* Read the output stream buffer from the point of the last read, up to a maximum length, copying it into the provided pointer.
* Returns the number of bytes read. This is only for use with the "internal" output stream configuration, which stores outputs
* in an internal buffer rather than writing them directly to stdout/stderr/file/tcp, and attempted use of this function with any
* other mode will produce an error.
*
* This is intended primarily for interactive use cases, where the frontend requires on-demand, unbuffered access to the output
* stream data.
*/
struct selene_u64_result_t selene_fetch_output(struct SeleneInstance *instance,
uint8_t *out_ptr,
uint64_t out_max_len);

/**
* Reads a bool future
*/
Expand Down Expand Up @@ -218,3 +231,10 @@ struct selene_void_result_t selene_rzz(struct SeleneInstance *instance,
struct selene_void_result_t selene_set_tc(struct SeleneInstance *instance, uint64_t tc);

struct selene_u64_result_t selene_shot_count(struct SeleneInstance *instance);

/**
* Writes metadata to the result stream, such as event hooks (metrics, instruction logs, etc).
* This happens upon shot end automatically, but can be triggered manually mid-shot if desired
* by calling this function (e.g. in interactive mode)
*/
struct selene_void_result_t selene_write_metadata(struct SeleneInstance *instance);
5 changes: 5 additions & 0 deletions selene-sim/python/selene_sim/interactive/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .full_stack import InteractiveFullStack
from .simulator import InteractiveSimulator
from .runtime import InteractiveRuntime

__all__ = ["InteractiveFullStack", "InteractiveSimulator", "InteractiveRuntime"]
Loading