use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
use super::functions::*;
use std::collections::{HashMap, VecDeque};
#[allow(dead_code)]
pub struct RecordWriter {
inner: BufferedWriter,
record_count: usize,
}
impl RecordWriter {
#[allow(dead_code)]
pub fn new(flush_threshold: usize) -> Self {
Self {
inner: BufferedWriter::new(flush_threshold),
record_count: 0,
}
}
#[allow(dead_code)]
pub fn write_record(&mut self, record: &str) {
self.inner.writeln(record);
self.record_count += 1;
}
#[allow(dead_code)]
pub fn record_count(&self) -> usize {
self.record_count
}
#[allow(dead_code)]
pub fn total_written(&self) -> usize {
self.inner.total_written()
}
#[allow(dead_code)]
pub fn flush(&mut self) {
self.inner.flush();
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Capability {
pub level: u32,
pub description: String,
}
#[allow(dead_code)]
impl Capability {
pub fn new(level: u32, description: impl Into<String>) -> Self {
Self {
level,
description: description.into(),
}
}
pub fn null() -> Self {
Self::new(0, "null")
}
pub fn read_only() -> Self {
Self::new(1, "read-only")
}
pub fn read_write() -> Self {
Self::new(2, "read-write")
}
pub fn full() -> Self {
Self::new(u32::MAX, "full")
}
pub fn is_sufficient_for(&self, required: u32) -> bool {
self.level >= required
}
pub fn attenuate(&self, max_level: u32) -> Capability {
Capability::new(
self.level.min(max_level),
format!("attenuated({})", max_level),
)
}
}
#[allow(dead_code)]
pub struct DelimiterSplitter {
buffer: Vec<u8>,
delimiter: u8,
}
impl DelimiterSplitter {
#[allow(dead_code)]
pub fn new(delimiter: u8) -> Self {
Self {
buffer: Vec::new(),
delimiter,
}
}
#[allow(dead_code)]
pub fn feed(&mut self, data: &[u8]) {
self.buffer.extend_from_slice(data);
}
#[allow(dead_code)]
pub fn drain(&mut self) -> Vec<Vec<u8>> {
let mut records = Vec::new();
while let Some(pos) = self.buffer.iter().position(|&b| b == self.delimiter) {
let record = self.buffer.drain(..pos).collect();
self.buffer.drain(..1);
records.push(record);
}
records
}
#[allow(dead_code)]
pub fn buffered_len(&self) -> usize {
self.buffer.len()
}
}
#[derive(Debug, Clone)]
pub struct FileMetadata {
pub path: String,
pub size: u64,
pub is_dir: bool,
pub is_file: bool,
pub read_only: bool,
}
impl FileMetadata {
pub fn regular_file(path: impl Into<String>, size: u64) -> Self {
Self {
path: path.into(),
size,
is_dir: false,
is_file: true,
read_only: false,
}
}
pub fn directory(path: impl Into<String>) -> Self {
Self {
path: path.into(),
size: 0,
is_dir: true,
is_file: false,
read_only: false,
}
}
pub fn with_read_only(mut self) -> Self {
self.read_only = true;
self
}
}
#[allow(dead_code)]
#[derive(Debug, Default, Clone)]
pub struct MockFs {
files: std::collections::HashMap<String, Vec<u8>>,
}
impl MockFs {
#[allow(dead_code)]
pub fn new() -> Self {
Self::default()
}
#[allow(dead_code)]
pub fn write(&mut self, path: &str, data: Vec<u8>) {
self.files.insert(path.to_string(), data);
}
#[allow(dead_code)]
pub fn write_str(&mut self, path: &str, content: &str) {
self.write(path, content.as_bytes().to_vec());
}
#[allow(dead_code)]
pub fn read(&self, path: &str) -> Result<Vec<u8>, IoError> {
self.files
.get(path)
.cloned()
.ok_or_else(|| IoError::not_found(path))
}
#[allow(dead_code)]
pub fn read_str(&self, path: &str) -> Result<String, IoError> {
let bytes = self.read(path)?;
String::from_utf8(bytes).map_err(|_| IoError::invalid_data("invalid UTF-8"))
}
#[allow(dead_code)]
pub fn exists(&self, path: &str) -> bool {
self.files.contains_key(path)
}
#[allow(dead_code)]
pub fn remove(&mut self, path: &str) -> bool {
self.files.remove(path).is_some()
}
#[allow(dead_code)]
pub fn list_paths(&self) -> Vec<&str> {
self.files.keys().map(String::as_str).collect()
}
#[allow(dead_code)]
pub fn file_size(&self, path: &str) -> Result<u64, IoError> {
self.files
.get(path)
.map(|v| v.len() as u64)
.ok_or_else(|| IoError::not_found(path))
}
}
#[allow(dead_code)]
pub struct HoareVerifier {
triples: Vec<(String, String, String)>,
}
#[allow(dead_code)]
impl HoareVerifier {
pub fn new() -> Self {
Self {
triples: Vec::new(),
}
}
pub fn add_triple(
&mut self,
op: impl Into<String>,
pre: impl Into<String>,
post: impl Into<String>,
) {
self.triples.push((op.into(), pre.into(), post.into()));
}
pub fn triple_count(&self) -> usize {
self.triples.len()
}
pub fn postcondition_of(&self, op: &str) -> Option<&str> {
self.triples
.iter()
.find(|(o, _, _)| o == op)
.map(|(_, _, post)| post.as_str())
}
pub fn has_triple(&self, op: &str) -> bool {
self.triples.iter().any(|(o, _, _)| o == op)
}
pub fn operations(&self) -> Vec<&str> {
self.triples.iter().map(|(o, _, _)| o.as_str()).collect()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IoErrorKind {
NotFound,
PermissionDenied,
ConnectionRefused,
TimedOut,
UnexpectedEof,
WriteZero,
InvalidData,
Other,
}
#[allow(dead_code)]
pub struct SessionChannel {
protocol: Vec<SessionAction>,
cursor: usize,
messages: Vec<String>,
}
#[allow(dead_code)]
impl SessionChannel {
pub fn new(protocol: Vec<SessionAction>) -> Self {
Self {
protocol,
cursor: 0,
messages: Vec::new(),
}
}
pub fn send(&mut self, msg: impl Into<String>) -> Result<(), String> {
if self.cursor >= self.protocol.len() {
return Err("protocol exhausted".to_string());
}
if self.protocol[self.cursor] != SessionAction::Send {
return Err(format!(
"protocol violation: expected {:?}, got Send",
self.protocol[self.cursor]
));
}
self.messages.push(msg.into());
self.cursor += 1;
Ok(())
}
pub fn recv(&mut self) -> Result<Option<String>, String> {
if self.cursor >= self.protocol.len() {
return Err("protocol exhausted".to_string());
}
if self.protocol[self.cursor] != SessionAction::Recv {
return Err(format!(
"protocol violation: expected {:?}, got Recv",
self.protocol[self.cursor]
));
}
self.cursor += 1;
Ok(self.messages.pop())
}
pub fn is_complete(&self) -> bool {
self.cursor >= self.protocol.len()
}
pub fn remaining_steps(&self) -> usize {
self.protocol.len().saturating_sub(self.cursor)
}
}
#[allow(dead_code)]
pub struct AsyncTaskQueue {
pending: std::collections::VecDeque<(usize, String)>,
completed: std::collections::HashMap<usize, String>,
next_id: usize,
}
#[allow(dead_code)]
impl AsyncTaskQueue {
pub fn new() -> Self {
Self {
pending: std::collections::VecDeque::new(),
completed: std::collections::HashMap::new(),
next_id: 0,
}
}
pub fn enqueue(&mut self, description: impl Into<String>) -> usize {
let id = self.next_id;
self.next_id += 1;
self.pending.push_back((id, description.into()));
id
}
pub fn complete_next(&mut self, result: impl Into<String>) -> Option<usize> {
if let Some((id, _)) = self.pending.pop_front() {
self.completed.insert(id, result.into());
Some(id)
} else {
None
}
}
pub fn result_of(&self, id: usize) -> Option<&str> {
self.completed.get(&id).map(String::as_str)
}
pub fn pending_count(&self) -> usize {
self.pending.len()
}
pub fn completed_count(&self) -> usize {
self.completed.len()
}
pub fn is_complete(&self, id: usize) -> bool {
self.completed.contains_key(&id)
}
}
#[derive(Debug, Clone)]
pub struct IoAction {
pub kind: IoActionKind,
pub result_type: Expr,
}
impl IoAction {
pub fn new(kind: IoActionKind, result_type: Expr) -> Self {
Self { kind, result_type }
}
pub fn println() -> Self {
Self::new(
IoActionKind::Println,
Expr::Const(Name::str("Unit"), vec![]),
)
}
pub fn read_line() -> Self {
Self::new(
IoActionKind::ReadStdin,
Expr::Const(Name::str("String"), vec![]),
)
}
pub fn exit(code: i32) -> Self {
Self::new(
IoActionKind::Exit(code),
Expr::Const(Name::str("Empty"), vec![]),
)
}
}
#[derive(Debug, Clone)]
pub struct IoError {
pub kind: IoErrorKind,
pub message: String,
}
impl IoError {
pub fn new(kind: IoErrorKind, message: impl Into<String>) -> Self {
Self {
kind,
message: message.into(),
}
}
pub fn not_found(path: &str) -> Self {
Self::new(IoErrorKind::NotFound, format!("file not found: {}", path))
}
pub fn permission_denied(path: &str) -> Self {
Self::new(
IoErrorKind::PermissionDenied,
format!("permission denied: {}", path),
)
}
pub fn unexpected_eof() -> Self {
Self::new(IoErrorKind::UnexpectedEof, "unexpected end of file")
}
pub fn invalid_data(msg: impl Into<String>) -> Self {
Self::new(IoErrorKind::InvalidData, msg)
}
}
#[allow(dead_code)]
pub struct StmLog {
reads: Vec<(usize, i64)>,
writes: Vec<(usize, i64)>,
aborted: bool,
}
#[allow(dead_code)]
impl StmLog {
pub fn new() -> Self {
Self {
reads: Vec::new(),
writes: Vec::new(),
aborted: false,
}
}
pub fn record_read(&mut self, cell_id: usize, value: i64) {
self.reads.push((cell_id, value));
}
pub fn record_write(&mut self, cell_id: usize, value: i64) {
self.writes.push((cell_id, value));
}
pub fn abort(&mut self) {
self.aborted = true;
}
pub fn is_aborted(&self) -> bool {
self.aborted
}
pub fn conflicts_with(&self, other: &StmLog) -> bool {
for (wid, _) in &self.writes {
for (owid, _) in &other.writes {
if wid == owid {
return true;
}
}
}
false
}
pub fn read_count(&self) -> usize {
self.reads.len()
}
pub fn write_count(&self) -> usize {
self.writes.len()
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum IoActionKind {
ReadStdin,
WriteStdout,
WriteStderr,
OpenRead(String),
OpenWrite(String),
Close,
Println,
Flush,
Sleep(u64),
Exit(i32),
}
pub struct BufferedReader {
data: Vec<u8>,
pos: usize,
capacity: usize,
}
impl BufferedReader {
pub fn new(data: Vec<u8>) -> Self {
Self {
capacity: data.len(),
data,
pos: 0,
}
}
#[allow(clippy::should_implement_trait)]
pub fn from_str(s: &str) -> Self {
Self::new(s.as_bytes().to_vec())
}
pub fn read_byte(&mut self) -> Option<u8> {
if self.pos < self.data.len() {
let b = self.data[self.pos];
self.pos += 1;
Some(b)
} else {
None
}
}
pub fn read_line(&mut self) -> Option<String> {
if self.pos >= self.data.len() {
return None;
}
let start = self.pos;
while self.pos < self.data.len() && self.data[self.pos] != b'\n' {
self.pos += 1;
}
if self.pos < self.data.len() {
self.pos += 1;
}
String::from_utf8(self.data[start..self.pos].to_vec()).ok()
}
pub fn read_to_string(&mut self) -> Result<String, IoError> {
let remaining = &self.data[self.pos..];
self.pos = self.data.len();
String::from_utf8(remaining.to_vec())
.map_err(|_| IoError::invalid_data("invalid UTF-8 sequence"))
}
pub fn read_exact(&mut self, n: usize) -> Result<Vec<u8>, IoError> {
if self.pos + n > self.data.len() {
return Err(IoError::unexpected_eof());
}
let slice = self.data[self.pos..self.pos + n].to_vec();
self.pos += n;
Ok(slice)
}
pub fn peek(&self) -> Option<u8> {
self.data.get(self.pos).copied()
}
pub fn is_eof(&self) -> bool {
self.pos >= self.data.len()
}
pub fn remaining(&self) -> usize {
self.data.len().saturating_sub(self.pos)
}
pub fn reset(&mut self) {
self.pos = 0;
}
pub fn skip(&mut self, n: usize) {
self.pos = (self.pos + n).min(self.data.len());
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn lines(&mut self) -> Vec<String> {
let mut result = Vec::new();
while let Some(line) = self.read_line() {
result.push(line);
}
result
}
}
#[allow(dead_code)]
#[derive(Debug, Default, Clone)]
pub struct EnvRegistry {
vars: std::collections::HashMap<String, String>,
}
impl EnvRegistry {
#[allow(dead_code)]
pub fn new() -> Self {
Self::default()
}
#[allow(dead_code)]
pub fn set(&mut self, key: &str, val: &str) {
self.vars.insert(key.to_string(), val.to_string());
}
#[allow(dead_code)]
pub fn get(&self, key: &str) -> Option<&str> {
self.vars.get(key).map(String::as_str)
}
#[allow(dead_code)]
pub fn remove(&mut self, key: &str) {
self.vars.remove(key);
}
#[allow(dead_code)]
pub fn keys(&self) -> Vec<&str> {
self.vars.keys().map(String::as_str).collect()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub enum SessionAction {
Send,
Recv,
}
pub struct BufferedWriter {
buffer: Vec<u8>,
flush_threshold: usize,
total_written: usize,
}
impl BufferedWriter {
pub fn new(flush_threshold: usize) -> Self {
Self {
buffer: Vec::new(),
flush_threshold,
total_written: 0,
}
}
pub fn default_threshold() -> Self {
Self::new(4096)
}
pub fn write_bytes(&mut self, data: &[u8]) {
self.buffer.extend_from_slice(data);
self.total_written += data.len();
if self.buffer.len() >= self.flush_threshold {
self.flush();
}
}
pub fn write_str(&mut self, s: &str) {
self.write_bytes(s.as_bytes());
}
pub fn writeln(&mut self, s: &str) {
self.write_str(s);
self.write_bytes(b"\n");
}
pub fn flush(&mut self) {
self.buffer.clear();
}
pub fn as_str(&self) -> Result<&str, IoError> {
std::str::from_utf8(&self.buffer)
.map_err(|_| IoError::invalid_data("buffer contains invalid UTF-8"))
}
pub fn buffered_len(&self) -> usize {
self.buffer.len()
}
pub fn total_written(&self) -> usize {
self.total_written
}
pub fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
}
#[derive(Debug, Default)]
pub struct IoActionPipeline {
actions: Vec<IoAction>,
}
impl IoActionPipeline {
pub fn new() -> Self {
Self::default()
}
pub fn push(&mut self, action: IoAction) {
self.actions.push(action);
}
pub fn len(&self) -> usize {
self.actions.len()
}
pub fn is_empty(&self) -> bool {
self.actions.is_empty()
}
pub fn actions(&self) -> &[IoAction] {
&self.actions
}
pub fn has_exit(&self) -> bool {
self.actions
.iter()
.any(|a| matches!(a.kind, IoActionKind::Exit(_)))
}
pub fn result_type(&self) -> Option<&Expr> {
self.actions.last().map(|a| &a.result_type)
}
pub fn clear(&mut self) {
self.actions.clear();
}
}