Skip to content

Commit

Permalink
TextFileEntityTextFileLink の実装
Browse files Browse the repository at this point in the history
  • Loading branch information
hayatroid committed Oct 17, 2024
1 parent 3159c4a commit 8e6a87b
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 68 deletions.
78 changes: 30 additions & 48 deletions judge-control-app/src/custom_file/text_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,69 +9,51 @@ use std::{

use super::traits::File;

struct FileAccess;

struct TextFileInner {
struct TextFileEntity {
path: PathBuf,
_parent: Option<TextFile>,
lock: Arc<RwLock<FileAccess>>,
}

impl Drop for TextFileInner {
impl File for TextFileEntity {
type InitArgs = String;
fn new(path: PathBuf, args: Self::InitArgs) -> anyhow::Result<Self> {
let mut file = std::fs::File::create(&path)?;
file.write_all(args.as_bytes())?;
Ok(Self { path })
}
fn create_symlink_to(&self, path: PathBuf) -> anyhow::Result<Self> {
unimplemented!();
}
}

impl Drop for TextFileEntity {
fn drop(&mut self) {
let _ = std::fs::remove_file(&self.path);
// ./text_file/tests.rs でのテスト用
eprintln!("{:?}", self.path);
std::fs::remove_file(&self.path);
eprintln!("Entity {:?} dropped.", self.path);
}
}

// TextFileInner を Arc でラップして使う.
//
// シンボリックリンク自体を子,リンク先を親と表現するとき,子は Arc<親> を持つ.
// (これにより子から drop することが保証されるはず?)
//
// オリジナルファイルには Arc<RwLock<FileAccess>> を新たに作成して持たせる.
// シンボリックリンク(子や孫すべて)にはその clone を持たせる.
// (元ファイルを根とする根付き木全体で 1 つの RwLock<FileAccess> を共有しているはず?)
#[derive(Clone)]
struct TextFile(Arc<TextFileInner>);
struct TextFileLink {
path: PathBuf,
entity: Arc<RwLock<TextFileEntity>>,
}

impl File for TextFile {
type InitArgs = String;
impl File for TextFileLink {
type InitArgs = Arc<RwLock<TextFileEntity>>;
fn new(path: PathBuf, args: Self::InitArgs) -> anyhow::Result<Self> {
// ファイルの作成・初期化
let mut file = std::fs::File::create(&path)?;
file.write_all(args.as_bytes())?;

// オリジナルファイルなので,親は存在しない.
// Arc<RwLock<FileAccess>> を新たに作成して持たせる.
let inner = TextFileInner {
std::os::unix::fs::symlink(&args.read().unwrap().path, &path)?;
Ok(Self {
path,
_parent: None,
lock: Arc::new(RwLock::new(FileAccess)),
};

Ok(TextFile(Arc::new(inner)))
entity: args.clone(),
})
}
fn create_symlink_to(&self, path: PathBuf) -> anyhow::Result<Self> {
// シンボリックリンクの作成
std::os::unix::fs::symlink(&self.0.path, &path)?;

// 自身の clone を子に持たせる.
// Arc<RwLock<FileAccess>> の clone を持たせる.
let inner = TextFileInner {
path,
_parent: Some(self.clone()),
lock: self.0.lock.clone(),
};

Ok(TextFile(Arc::new(inner)))
Self::new(path, self.entity.clone())
}
}

impl Drop for TextFile {
impl Drop for TextFileLink {
fn drop(&mut self) {
// Arc<TextFileInner> が drop したときに呼び出すと,複数回呼び出されてしまう.
// TextFileInner が drop したときに呼び出されるようにしたい.
std::fs::remove_file(&self.path);
eprintln!("Link {:?} dropped.", self.path);
}
}
38 changes: 18 additions & 20 deletions judge-control-app/src/custom_file/text_file/tests.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
use std::path::PathBuf;
use std::{
path::PathBuf,
sync::{Arc, RwLock},
};

use crate::custom_file::traits::File;

use super::TextFile;
use crate::custom_file::{
text_file::{TextFileEntity, TextFileLink},
traits::File,
};

#[test]
fn drop_from_leaves() -> anyhow::Result<()> {
let v = {
let a = TextFile::new(PathBuf::from("a.txt"), "hello!".to_string())?;

let b1 = a.create_symlink_to(PathBuf::from("b1.txt"))?;
let b2 = a.create_symlink_to(PathBuf::from("b2.txt"))?;
let b3 = a.create_symlink_to(PathBuf::from("b3.txt"))?;
fn drop_not_leaf_node() -> anyhow::Result<()> {
let a = Arc::new(RwLock::new(TextFileEntity::new(
PathBuf::from("a.txt"),
"hello".to_string(),
)?));

let c1 = b1.create_symlink_to(PathBuf::from("c1.txt"))?;
let c2 = b1.create_symlink_to(PathBuf::from("c2.txt"))?;
let c3 = b1.create_symlink_to(PathBuf::from("c3.txt"))?;
let b = TextFileLink::new(PathBuf::from("b.txt"), a.clone())?;

vec![a, b1, b2, b3, c1, c2, c3];
};
let c = b.create_symlink_to(PathBuf::from("c.txt"))?;

// たとえば
// "b2.txt"→ "b3.txt"→ "c1.txt"→ "c2.txt"→ "c3.txt"→ "b1.txt"→ "a.txt"
// のように,葉から drop することが確認できる.
drop(v);
drop(b);

println!("b is dropped.");

Ok(())
}

0 comments on commit 8e6a87b

Please sign in to comment.