use crate::app::file::{FileStatus, FileType, Permissions};
use crate::app::parse::parser::SingleHeaderError;
use crate::app::{MaybeAsync, ObjectParseError, Shutdown, Timestamp};
use crate::master::TaskError;
use std::fmt::Debug;
#[derive(Clone, Debug)]
pub struct FileCredentials {
pub user_name: String,
pub password: String,
}
#[derive(Clone, Debug)]
pub struct FileInfo {
pub name: String,
pub file_type: FileType,
pub size: u32,
pub time_created: Timestamp,
pub permissions: Permissions,
}
#[derive(Copy, Clone, Debug)]
pub struct FileReadConfig {
pub max_block_size: u16,
pub max_file_size: usize,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FileWriteMode {
Write,
Append,
}
impl From<FileWriteMode> for FileMode {
fn from(value: FileWriteMode) -> Self {
match value {
FileWriteMode::Write => Self::Write,
FileWriteMode::Append => Self::Append,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct DirReadConfig {
pub max_block_size: u16,
pub max_file_size: usize,
}
impl From<DirReadConfig> for FileReadConfig {
fn from(value: DirReadConfig) -> Self {
Self {
max_block_size: value.max_block_size,
max_file_size: value.max_file_size,
}
}
}
impl FileReadConfig {
pub fn new() -> Self {
Self {
max_block_size: u16::MAX,
max_file_size: usize::MAX,
}
}
}
impl DirReadConfig {
pub const DEFAULT_MAX_SIZE: usize = 2048;
pub fn new() -> Self {
Self {
max_block_size: u16::MAX,
max_file_size: Self::DEFAULT_MAX_SIZE,
}
}
}
impl Default for FileReadConfig {
fn default() -> Self {
Self::new()
}
}
impl Default for DirReadConfig {
fn default() -> Self {
Self::new()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(not(feature = "ffi"), non_exhaustive)]
pub enum FileError {
BadResponse,
BadStatus(FileStatus),
WrongHandle,
NoPermission,
BadBlockNum,
AbortByUser,
MaxLengthExceeded,
TaskError(TaskError),
}
impl From<tokio::sync::oneshot::error::RecvError> for FileError {
fn from(_: tokio::sync::oneshot::error::RecvError) -> Self {
Self::TaskError(TaskError::Shutdown)
}
}
impl From<Shutdown> for FileError {
fn from(_: Shutdown) -> Self {
Self::TaskError(TaskError::Shutdown)
}
}
impl From<ObjectParseError> for FileError {
fn from(value: ObjectParseError) -> Self {
FileError::TaskError(value.into())
}
}
impl From<SingleHeaderError> for FileError {
fn from(_: SingleHeaderError) -> Self {
Self::TaskError(TaskError::UnexpectedResponseHeaders)
}
}
impl From<FileError> for TaskError {
fn from(err: FileError) -> Self {
match err {
FileError::TaskError(err) => err,
_ => TaskError::UnexpectedResponseHeaders,
}
}
}
impl From<TaskError> for FileError {
fn from(err: TaskError) -> Self {
FileError::TaskError(err)
}
}
impl std::fmt::Display for FileError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
FileError::BadResponse => f.write_str("bad response data"),
FileError::BadStatus(s) => write!(f, "bad status code: {s:?}"),
FileError::NoPermission => f.write_str("no permission"),
FileError::BadBlockNum => f.write_str("bad block number"),
FileError::AbortByUser => f.write_str("aborted by user"),
FileError::TaskError(t) => Debug::fmt(&t, f),
FileError::MaxLengthExceeded => f.write_str("exceeded maximum received length"),
FileError::WrongHandle => {
f.write_str("file handle returned by outstation did not match the request")
}
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FileMode {
Null,
Read,
Write,
Append,
Reserved(u16),
}
impl FileMode {
pub(crate) fn new(value: u16) -> Self {
match value {
0 => Self::Null,
1 => Self::Read,
2 => Self::Write,
3 => Self::Append,
_ => Self::Reserved(value),
}
}
pub(crate) fn to_u16(self) -> u16 {
match self {
Self::Null => 0,
Self::Read => 1,
Self::Write => 2,
Self::Append => 3,
Self::Reserved(x) => x,
}
}
}
impl std::error::Error for FileError {}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FileAction {
Abort,
Continue,
}
impl FileAction {
pub(crate) fn is_abort(self) -> bool {
match self {
Self::Abort => true,
Self::Continue => false,
}
}
}
pub trait FileReader: Send + Sync + 'static {
fn opened(&mut self, size: u32) -> FileAction;
fn block_received(&mut self, block_num: u32, data: &[u8]) -> MaybeAsync<FileAction>;
fn aborted(&mut self, err: FileError);
fn completed(&mut self);
}
#[derive(Copy, Clone, Debug)]
pub struct AuthKey(u32);
impl From<AuthKey> for u32 {
fn from(value: AuthKey) -> Self {
value.0
}
}
impl AuthKey {
pub fn new(value: u32) -> Self {
Self(value)
}
pub fn none() -> Self {
Self(0)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FileHandle(u32);
impl From<FileHandle> for u32 {
fn from(value: FileHandle) -> Self {
value.0
}
}
impl FileHandle {
pub const fn new(value: u32) -> Self {
Self(value)
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct BlockNumber(u32);
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FailedBlockIncrement;
impl std::fmt::Display for FailedBlockIncrement {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"File block number is at maximum value of {} and cannot be incremented",
BlockNumber::MAX_VALUE
)
}
}
impl std::error::Error for FailedBlockIncrement {}
impl BlockNumber {
const TOP_BIT: u32 = 0x80_00_00_00;
pub const MAX_VALUE: u32 = !Self::TOP_BIT;
pub fn is_last(self) -> bool {
(self.0 & Self::TOP_BIT) != 0
}
pub fn set_last(&mut self) {
self.0 |= Self::TOP_BIT;
}
pub fn increment(&mut self) -> Result<(), FailedBlockIncrement> {
let top_bit = self.0 & Self::TOP_BIT;
let bottom_bits = self.bottom_bits();
if bottom_bits < Self::MAX_VALUE {
self.0 = (self.bottom_bits() + 1) | top_bit;
Ok(())
} else {
Err(FailedBlockIncrement)
}
}
#[cfg(feature = "ffi")]
pub fn from_ffi_raw(raw: u32) -> BlockNumber {
Self::new(raw)
}
pub(crate) fn new(raw: u32) -> BlockNumber {
Self(raw)
}
pub(crate) fn bottom_bits(self) -> u32 {
self.0 & Self::MAX_VALUE
}
pub(crate) fn wire_value(self) -> u32 {
self.0
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct OpenFile {
pub file_handle: FileHandle,
pub file_size: u32,
pub max_block_size: u16,
}