Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
werdl committed May 30, 2024
0 parents commit a2f0f72
Show file tree
Hide file tree
Showing 7 changed files with 313 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "file"
version = "0.1.0"
edition = "2021"

[dependencies]
bitflags = "2.5.0"
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# file
> An alternative filesystem API for Rust, for simplity.
## Usage
```rust
use file::File; // all functions are implemented on File struct
use file::FileOptions; // options for file operations, a bitflag but can also be used like a builder


// read a file
let file: File = FileOptions::Read.open("README.md").unwrap();

let u8_vec: Vec<u8> = file.read().unwrap();
let string: String = file.read_to_string().unwrap();


// read to a file, then write it back prefixed with "Hello, "
let file: File = (FileOptions::Read | FileOptions::Write).open("README.md").unwrap();

let mut string: String = file.read_to_string().unwrap();

string = format!("Hello, {}", string);

let _ = file.seek(0);

file.write(string.as_bytes()).unwrap();


// create a file and write to it
let file: File = FileOptions::new()
.write(true)
.create(true)
.open("hello.txt");

let _ = file.write("Hello, world!");
```
Empty file added file.txt
Empty file.
229 changes: 229 additions & 0 deletions src/defs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
use std::io::{Read, Seek, Write};

use bitflags::bitflags;

bitflags! {
#[derive(Debug, Clone, Copy)]
pub struct FileOptions: u32 {
const Read = 0b00000001;
const Write = 0b00000010;
const Create = 0b00000100;
const ExclusiveCreate = 0b00001000;
const Truncate = 0b00010000;
const Append = 0b00100000;

const Uninitialized = 0b10000000;
}
}

impl FileOptions {
fn is_initialized(&self) -> bool {
!self.contains(FileOptions::Uninitialized)
}

pub fn read(self, set: bool) -> FileOptions {
if set {
(self - FileOptions::Uninitialized) | FileOptions::Read
} else {
self
}
}

pub fn write(self, set: bool) -> FileOptions {
if set {
(self - FileOptions::Uninitialized) | FileOptions::Write
} else {
self
}
}

pub fn create(self, set: bool) -> FileOptions {
if set {
(self - FileOptions::Uninitialized) | FileOptions::Create
} else {
self
}
}

pub fn exclusive_create(self, set: bool) -> FileOptions {
if set {
(self - FileOptions::Uninitialized) | FileOptions::ExclusiveCreate
} else {
self
}
}

pub fn truncate(self, set: bool) -> FileOptions {
if set {
(self - FileOptions::Uninitialized) | FileOptions::Truncate
} else {
self
}
}

pub fn append(self, set: bool) -> FileOptions {
if set {
(self - FileOptions::Uninitialized) | FileOptions::Append
} else {
self
}
}

pub fn new() -> FileOptions {
FileOptions::Uninitialized
}

pub fn open<T>(self, file_name: T) -> Result<File, FileError>
where
T: ToString,
{
if self.contains(FileOptions::Uninitialized) {
return Err(FileError {
message: "FileOptions uninitialized".to_string(),
file_options: self,
file_name: file_name.to_string(),
underlying_error: std::io::Error::new(std::io::ErrorKind::InvalidInput, "FileOptions uninitialized"),
});
}

let openoptions = std::fs::OpenOptions::new()
.read(self.contains(FileOptions::Read))
.write(self.contains(FileOptions::Write))
.create(self.contains(FileOptions::Create))
.create_new(self.contains(FileOptions::ExclusiveCreate))
.truncate(self.contains(FileOptions::Truncate))
.append(self.contains(FileOptions::Append))
.open(file_name.to_string());

match openoptions {
Ok(file) => Ok(File {
file_name: file_name.to_string(),
file_options: self,
underlying_file: file,
}),
Err(e) => Err(FileError {
message: e.to_string(),
file_options: self,
file_name: file_name.to_string(),
underlying_error: e,
}),
}

}
}

pub struct File {
file_name: String,
file_options: FileOptions,
pub underlying_file: std::fs::File,
}

// error struct
#[derive(Debug)]
pub struct FileError {
message: String,
file_options: FileOptions,
file_name: String,
underlying_error: std::io::Error,
}

impl File {
pub fn read(&mut self) -> Result<String, FileError> {
let mut buffer = String::new();
match self.underlying_file.read_to_string(&mut buffer) {
Ok(_) => {
println!("Read {} bytes from file", buffer.len());
Ok(buffer)
},
Err(e) => Err(FileError {
message: e.to_string(),
file_options: self.file_options,
file_name: self.file_name.clone(),
underlying_error: e,
}),
}
}

pub fn read_u8(&mut self) -> Result<Vec<u8>, FileError> {
let string = self.read();

match string {
Ok(s) => Ok(s.into_bytes()),
Err(e) => Err(e),
}
}

pub fn write<T: ToString>(&mut self, data: T) -> Result<(), FileError> {
match self.underlying_file.write_all(data.to_string().as_bytes()) {
Ok(_) => Ok(()),
Err(e) => Err(FileError {
message: e.to_string(),
file_options: self.file_options,
file_name: self.file_name.clone(),
underlying_error: e,
}),
}
}

pub fn write_u8(&mut self, data: Vec<u8>) -> Result<(), FileError> {
let string = String::from_utf8(data);

match string {
Ok(s) => self.write(s),
Err(e) => Err(FileError {
message: e.to_string(),
file_options: self.file_options,
file_name: self.file_name.clone(),
underlying_error: std::io::Error::new(std::io::ErrorKind::InvalidData, e),
}),
}
}

pub fn flush(&mut self) -> Result<(), FileError> {
match self.underlying_file.flush() {
Ok(_) => Ok(()),
Err(e) => Err(FileError {
message: e.to_string(),
file_options: self.file_options,
file_name: self.file_name.clone(),
underlying_error: e,
}),
}
}

pub fn delete(self) -> Result<(), FileError> {
match std::fs::remove_file(self.file_name.clone()) {
Ok(_) => Ok(()),
Err(e) => Err(FileError {
message: e.to_string(),
file_options: self.file_options,
file_name: self.file_name.clone(),
underlying_error: e,
}),
}
}

pub fn close(self) -> Result<(), FileError> {
match self.underlying_file.sync_all() {
Ok(_) => Ok(()),
Err(e) => Err(FileError {
message: e.to_string(),
file_options: self.file_options,
file_name: self.file_name.clone(),
underlying_error: e,
}),
}
}

pub fn seek(&mut self, pos: u32) -> Result<u64, FileError> {
match self.underlying_file.seek(std::io::SeekFrom::Start(pos as u64)) {
Ok(pos) => Ok(pos),
Err(e) => Err(FileError {
message: e.to_string(),
file_options: self.file_options,
file_name: self.file_name.clone(),
underlying_error: e,
}),
}
}
}
24 changes: 24 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
mod defs;


mod tests {
use crate::defs::{File, FileOptions};
use std::io::Read;


#[test]
fn open() {
let file = (FileOptions::Create | FileOptions::Write).open("file.txt");
assert_eq!(file.is_ok(), true);
}

#[test]
fn open_and_attempt_read() {
let file = (FileOptions::Read).open("README.md");
assert_eq!(file.is_ok(), true);
let mut file: File = file.unwrap();

// read the file
let contents = file.read();
}
}

0 comments on commit a2f0f72

Please sign in to comment.