Files
hakorune/src/boxes/file/mod.rs

179 lines
5.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! FileBox 📁 - ファイルI/OPathBox/DirBoxとセット
// Nyashの箱システムによるファイル入出力を提供します。
// 参考: 既存Boxの設計思想
use crate::box_trait::{BoolBox, BoxBase, BoxCore, NyashBox, StringBox};
use std::any::Any;
use std::fs::{File, OpenOptions};
use std::io::{Read, Result, Write};
use std::sync::RwLock;
#[derive(Debug)]
pub struct FileBox {
file: RwLock<File>,
path: String,
base: BoxBase,
}
impl Clone for FileBox {
fn clone(&self) -> Self {
// File handles can't be easily cloned, so we'll reopen the file
match Self::open(&self.path) {
Ok(new_file_box) => new_file_box,
Err(_) => {
// Fallback to default if reopening fails
Self::new()
}
}
}
}
impl FileBox {
pub fn new() -> Self {
// Create a default FileBox for delegation dispatch
// Uses a temporary file for built-in Box inheritance dispatch
let temp_path = "/tmp/nyash_temp_file";
match Self::open(temp_path) {
Ok(file_box) => file_box,
Err(_) => {
// Fallback: create with empty file handle - only for dispatch
use std::fs::OpenOptions;
let file = OpenOptions::new()
.create(true)
.write(true)
.read(true)
.open("/dev/null")
.unwrap_or_else(|_| File::open("/dev/null").unwrap());
FileBox {
file: RwLock::new(file),
path: String::new(),
base: BoxBase::new(),
}
}
}
}
pub fn open(path: &str) -> Result<Self> {
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)?;
Ok(FileBox {
file: RwLock::new(file),
path: path.to_string(),
base: BoxBase::new(),
})
}
pub fn read_to_string(&self) -> Result<String> {
let mut file = self.file.write().unwrap();
let mut s = String::new();
file.read_to_string(&mut s)?;
Ok(s)
}
pub fn write_all(&self, buf: &[u8]) -> Result<()> {
let mut file = self.file.write().unwrap();
file.write_all(buf)
}
/// ファイルの内容を読み取る
pub fn read(&self) -> Box<dyn NyashBox> {
match self.read_to_string() {
Ok(content) => Box::new(StringBox::new(&content)),
Err(e) => Box::new(StringBox::new(&format!("Error reading file: {}", e))),
}
}
/// ファイルに内容を書き込む
pub fn write(&self, content: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
let content_str = content.to_string_box().value;
match self.write_all(content_str.as_bytes()) {
Ok(()) => Box::new(StringBox::new("ok")),
Err(e) => Box::new(StringBox::new(&format!("Error writing file: {}", e))),
}
}
/// ファイルが存在するかチェック
pub fn exists(&self) -> Box<dyn NyashBox> {
use std::path::Path;
Box::new(BoolBox::new(Path::new(&self.path).exists()))
}
/// ファイルを削除
pub fn delete(&self) -> Box<dyn NyashBox> {
match std::fs::remove_file(&self.path) {
Ok(()) => Box::new(StringBox::new("ok")),
Err(e) => Box::new(StringBox::new(&format!("Error deleting file: {}", e))),
}
}
/// ファイルをコピー
pub fn copy(&self, dest: &str) -> Box<dyn NyashBox> {
match std::fs::copy(&self.path, dest) {
Ok(_) => Box::new(StringBox::new("ok")),
Err(e) => Box::new(StringBox::new(&format!("Error copying file: {}", e))),
}
}
}
impl BoxCore for FileBox {
fn box_id(&self) -> u64 {
self.base.id
}
fn parent_type_id(&self) -> Option<std::any::TypeId> {
self.base.parent_type_id
}
fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "FileBox({})", self.path)
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl NyashBox for FileBox {
fn clone_box(&self) -> Box<dyn NyashBox> {
// Note: Cannot truly clone a File handle, so create a new one to the same path
match FileBox::open(&self.path) {
Ok(new_file) => Box::new(new_file),
Err(_) => Box::new(crate::box_trait::VoidBox::new()), // Return void on error
}
}
/// 仮実装: clone_boxと同じ後で修正
fn share_box(&self) -> Box<dyn NyashBox> {
self.clone_box()
}
fn to_string_box(&self) -> StringBox {
StringBox::new(format!("FileBox({})", self.path))
}
fn type_name(&self) -> &'static str {
"FileBox"
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_file) = other.as_any().downcast_ref::<FileBox>() {
BoolBox::new(self.path == other_file.path)
} else {
BoolBox::new(false)
}
}
}
impl std::fmt::Display for FileBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}