From c7b2c5a14073dd382c4fc0b13d563658cf55de03 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABlle=20MARTIN?= <maelle.martin@proton.me>
Date: Tue, 20 Aug 2024 18:57:42 +0200
Subject: [PATCH] SCRIPT: Extract the xdg part from vvs_utils and add code to
 write the result into a file

---
 src/Rust/Cargo.lock                           | 12 +++++
 src/Rust/Cargo.toml                           |  1 +
 src/Rust/vvs_ass/src/elements/mod.rs          |  7 ++-
 src/Rust/vvs_cli/Cargo.toml                   |  1 +
 src/Rust/vvs_cli/src/config.rs                |  2 +-
 src/Rust/vvs_cli/src/main.rs                  |  9 +++-
 src/Rust/vvs_parser/src/lib.rs                |  1 +
 src/Rust/vvs_parser_derive/src/lib.rs         |  1 +
 src/Rust/vvs_procmacro/src/lib.rs             |  2 +
 src/Rust/vvs_runtime/src/jit.rs               |  2 +-
 src/Rust/vvs_shortstring/src/lib.rs           |  2 +
 src/Rust/vvs_utils/src/lib.rs                 |  5 +-
 src/Rust/vvs_xdg/Cargo.toml                   | 14 ++++++
 .../src/xdg => vvs_xdg/src}/config.rs         |  2 +-
 .../{vvs_utils => vvs_xdg}/src/file/lock.rs   |  2 +-
 .../{vvs_utils => vvs_xdg}/src/file/mod.rs    |  0
 .../{vvs_utils => vvs_xdg}/src/file/temp.rs   | 49 +++++++++++++++----
 .../src/xdg => vvs_xdg/src}/folders.rs        |  9 ++--
 .../src/xdg/mod.rs => vvs_xdg/src/lib.rs}     |  2 +
 .../src/xdg => vvs_xdg/src}/options.rs        |  0
 .../src/xdg => vvs_xdg/src}/paths.rs          |  0
 .../src/xdg => vvs_xdg/src}/tests.rs          |  0
 .../src/xdg => vvs_xdg/src}/traits.rs         |  0
 23 files changed, 98 insertions(+), 25 deletions(-)
 create mode 100644 src/Rust/vvs_xdg/Cargo.toml
 rename src/Rust/{vvs_utils/src/xdg => vvs_xdg/src}/config.rs (99%)
 rename src/Rust/{vvs_utils => vvs_xdg}/src/file/lock.rs (99%)
 rename src/Rust/{vvs_utils => vvs_xdg}/src/file/mod.rs (100%)
 rename src/Rust/{vvs_utils => vvs_xdg}/src/file/temp.rs (74%)
 rename src/Rust/{vvs_utils/src/xdg => vvs_xdg/src}/folders.rs (98%)
 rename src/Rust/{vvs_utils/src/xdg/mod.rs => vvs_xdg/src/lib.rs} (98%)
 rename src/Rust/{vvs_utils/src/xdg => vvs_xdg/src}/options.rs (100%)
 rename src/Rust/{vvs_utils/src/xdg => vvs_xdg/src}/paths.rs (100%)
 rename src/Rust/{vvs_utils/src/xdg => vvs_xdg/src}/tests.rs (100%)
 rename src/Rust/{vvs_utils/src/xdg => vvs_xdg/src}/traits.rs (100%)

diff --git a/src/Rust/Cargo.lock b/src/Rust/Cargo.lock
index 08c11d2e..455af85e 100644
--- a/src/Rust/Cargo.lock
+++ b/src/Rust/Cargo.lock
@@ -1042,6 +1042,7 @@ dependencies = [
  "vvs_parser",
  "vvs_runtime",
  "vvs_utils",
+ "vvs_xdg",
 ]
 
 [[package]]
@@ -1181,6 +1182,17 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "vvs_xdg"
+version = "0.5.0"
+dependencies = [
+ "anyhow",
+ "log",
+ "serde",
+ "thiserror",
+ "vvs_utils",
+]
+
 [[package]]
 name = "walkdir"
 version = "2.5.0"
diff --git a/src/Rust/Cargo.toml b/src/Rust/Cargo.toml
index 6d16464d..34908dc6 100644
--- a/src/Rust/Cargo.toml
+++ b/src/Rust/Cargo.toml
@@ -37,6 +37,7 @@ vvs_parser        = { path = "vvs_parser"        }
 vvs_procmacro     = { path = "vvs_procmacro"     }
 vvs_utils         = { path = "vvs_utils"         }
 vvs_font          = { path = "vvs_font"          }
+vvs_xdg           = { path = "vvs_xdg"           }
 vvs_ass           = { path = "vvs_ass"           }
 vvs_runtime       = { path = "vvs_runtime"       }
 vvs_llvm          = { path = "vvs_llvm"          }
diff --git a/src/Rust/vvs_ass/src/elements/mod.rs b/src/Rust/vvs_ass/src/elements/mod.rs
index d585f9a2..703a3526 100644
--- a/src/Rust/vvs_ass/src/elements/mod.rs
+++ b/src/Rust/vvs_ass/src/elements/mod.rs
@@ -5,7 +5,7 @@ mod syllabe;
 pub use self::{aux_table::*, line::*, syllabe::*};
 
 use crate::{definitions::ScriptInfoKey, ASSStyle};
-use std::collections::HashMap;
+use std::{collections::HashMap, fs, io};
 
 #[derive(Debug, Clone)]
 pub struct ASSContainer<T: AuxTable> {
@@ -24,4 +24,9 @@ impl<T: AuxTable> ASSContainer<T> {
     ) -> Self {
         Self { lines: lines.into_iter().collect(), script_info, styles }
     }
+
+    /// Write the content of the container into a file as an ASS file.
+    pub fn write_ass_to_file(&self, file: &mut fs::File) -> io::Result<()> {
+        todo!()
+    }
 }
diff --git a/src/Rust/vvs_cli/Cargo.toml b/src/Rust/vvs_cli/Cargo.toml
index 9b915097..bd8e31db 100644
--- a/src/Rust/vvs_cli/Cargo.toml
+++ b/src/Rust/vvs_cli/Cargo.toml
@@ -13,6 +13,7 @@ path = "src/main.rs"
 
 [dependencies]
 vvs_ass.workspace       = true
+vvs_xdg.workspace       = true
 vvs_font.workspace      = true
 vvs_utils.workspace     = true
 vvs_parser.workspace    = true
diff --git a/src/Rust/vvs_cli/src/config.rs b/src/Rust/vvs_cli/src/config.rs
index fd5718aa..5e51a9b2 100644
--- a/src/Rust/vvs_cli/src/config.rs
+++ b/src/Rust/vvs_cli/src/config.rs
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
 use std::path::PathBuf;
 use thiserror::Error;
 use vvs_utils::*;
-use xdg::XDGConfigFileSerde;
+use vvs_xdg::XDGConfigFileSerde;
 
 #[derive(Debug, Serialize, Deserialize)]
 pub struct ConfigKaraMaker {
diff --git a/src/Rust/vvs_cli/src/main.rs b/src/Rust/vvs_cli/src/main.rs
index 154af093..0fe4127f 100644
--- a/src/Rust/vvs_cli/src/main.rs
+++ b/src/Rust/vvs_cli/src/main.rs
@@ -1,3 +1,5 @@
+#![forbid(unsafe_code)]
+
 //! The VivyScript cli
 
 use anyhow::{Context as _, Result};
@@ -10,7 +12,7 @@ use vvs_cli::{
 };
 use vvs_codegen::lowerer;
 use vvs_parser::prelude::*;
-use vvs_utils::xdg::*;
+use vvs_xdg::{file::TempFile, XDGConfig, XDGConfigMergedSilent};
 
 fn print_font(name: impl AsRef<Path>, font: &[u8]) -> Result<()> {
     let name = name.as_ref();
@@ -87,6 +89,7 @@ fn main() -> Result<()> {
     }
 
     let jit = vvs_runtime::JIT::new()?;
+    let mut file = TempFile::new("vvcc")?;
     jit.with_module(
         lowerer::Lowerer::new(&jit.ctx(), &output.main.name)?
             .declare_globals(output.declared_functions())?
@@ -98,7 +101,9 @@ fn main() -> Result<()> {
     .run_on_file(
         vvs_ass::ass_container_from_file(ass_file.context("no subtitle file to run the script on")?)
             .context("failed to parse the subtitle file")?,
-    )?;
+    )?
+    .write_ass_to_file(&mut file)?;
 
+    println!("output file ........ {}", file.leak().path().display());
     Ok(())
 }
diff --git a/src/Rust/vvs_parser/src/lib.rs b/src/Rust/vvs_parser/src/lib.rs
index 1fbe49d1..4d609446 100644
--- a/src/Rust/vvs_parser/src/lib.rs
+++ b/src/Rust/vvs_parser/src/lib.rs
@@ -1,3 +1,4 @@
+#![forbid(unsafe_code)]
 #![warn(missing_docs)]
 #![allow(clippy::large_enum_variant)]
 
diff --git a/src/Rust/vvs_parser_derive/src/lib.rs b/src/Rust/vvs_parser_derive/src/lib.rs
index d62ebbc2..67e7bf2b 100644
--- a/src/Rust/vvs_parser_derive/src/lib.rs
+++ b/src/Rust/vvs_parser_derive/src/lib.rs
@@ -1,3 +1,4 @@
+#![forbid(unsafe_code)]
 #![recursion_limit = "128"]
 
 extern crate proc_macro;
diff --git a/src/Rust/vvs_procmacro/src/lib.rs b/src/Rust/vvs_procmacro/src/lib.rs
index 3085206b..c3a81cd2 100644
--- a/src/Rust/vvs_procmacro/src/lib.rs
+++ b/src/Rust/vvs_procmacro/src/lib.rs
@@ -1,3 +1,5 @@
+#![forbid(unsafe_code)]
+
 mod enums;
 mod vvrt;
 
diff --git a/src/Rust/vvs_runtime/src/jit.rs b/src/Rust/vvs_runtime/src/jit.rs
index 411ad78e..6b029df2 100644
--- a/src/Rust/vvs_runtime/src/jit.rs
+++ b/src/Rust/vvs_runtime/src/jit.rs
@@ -139,7 +139,7 @@ impl JIT {
     }
 
     /// Run the program on an ass file.
-    pub fn run_on_file(&self, ass: ASSContainer<VVRTTable>) -> anyhow::Result<&Self> {
+    pub fn run_on_file(&self, ass: ASSContainer<VVRTTable>) -> anyhow::Result<ASSContainer<VVRTTable>> {
         unimplemented!("use the ASS container and insert it into the JIT: {ass:#?}")
     }
 }
diff --git a/src/Rust/vvs_shortstring/src/lib.rs b/src/Rust/vvs_shortstring/src/lib.rs
index 130edaee..648d096b 100644
--- a/src/Rust/vvs_shortstring/src/lib.rs
+++ b/src/Rust/vvs_shortstring/src/lib.rs
@@ -1,3 +1,5 @@
+#![forbid(unsafe_code)]
+
 //! A small string, with short string optimization.
 
 use serde::{Deserialize, Serialize};
diff --git a/src/Rust/vvs_utils/src/lib.rs b/src/Rust/vvs_utils/src/lib.rs
index f7dc7380..81a9702c 100644
--- a/src/Rust/vvs_utils/src/lib.rs
+++ b/src/Rust/vvs_utils/src/lib.rs
@@ -1,12 +1,11 @@
+#![forbid(unsafe_code)]
+
 mod angles;
 mod assert;
 mod conds;
 mod minmax;
 mod rand;
 
-pub mod file;
-pub mod xdg;
-
 pub use angles::*;
 pub use conds::*;
 pub use minmax::*;
diff --git a/src/Rust/vvs_xdg/Cargo.toml b/src/Rust/vvs_xdg/Cargo.toml
new file mode 100644
index 00000000..4389a7c4
--- /dev/null
+++ b/src/Rust/vvs_xdg/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name              = "vvs_xdg"
+description       = "Utility for manipulating the XDG standard"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+
+[dependencies]
+vvs_utils.workspace = true
+thiserror.workspace = true
+anyhow.workspace    = true
+serde.workspace     = true
+log.workspace       = true
diff --git a/src/Rust/vvs_utils/src/xdg/config.rs b/src/Rust/vvs_xdg/src/config.rs
similarity index 99%
rename from src/Rust/vvs_utils/src/xdg/config.rs
rename to src/Rust/vvs_xdg/src/config.rs
index 0c70a533..b48c6f60 100644
--- a/src/Rust/vvs_utils/src/xdg/config.rs
+++ b/src/Rust/vvs_xdg/src/config.rs
@@ -1,7 +1,7 @@
 //! Utilities to extend the [XDGFolder] thing with config files: take into account the
 //! deserialization, merge of configs and others.
 
-use crate::xdg::{MaybeFolderList, XDGConfigFileSerde, XDGError, XDGFindBehaviour, XDGFolder};
+use crate::{MaybeFolderList, XDGConfigFileSerde, XDGError, XDGFindBehaviour, XDGFolder};
 use std::{fs, marker};
 
 /// Search configurations in all config folders and merge them.
diff --git a/src/Rust/vvs_utils/src/file/lock.rs b/src/Rust/vvs_xdg/src/file/lock.rs
similarity index 99%
rename from src/Rust/vvs_utils/src/file/lock.rs
rename to src/Rust/vvs_xdg/src/file/lock.rs
index 9d17fdc9..4c563bcb 100644
--- a/src/Rust/vvs_utils/src/file/lock.rs
+++ b/src/Rust/vvs_xdg/src/file/lock.rs
@@ -1,4 +1,4 @@
-use crate::xdg::*;
+use crate::*;
 use std::{
     collections::hash_map::DefaultHasher,
     fs::{File, OpenOptions},
diff --git a/src/Rust/vvs_utils/src/file/mod.rs b/src/Rust/vvs_xdg/src/file/mod.rs
similarity index 100%
rename from src/Rust/vvs_utils/src/file/mod.rs
rename to src/Rust/vvs_xdg/src/file/mod.rs
diff --git a/src/Rust/vvs_utils/src/file/temp.rs b/src/Rust/vvs_xdg/src/file/temp.rs
similarity index 74%
rename from src/Rust/vvs_utils/src/file/temp.rs
rename to src/Rust/vvs_xdg/src/file/temp.rs
index 0a5dcd0b..dc0d36a6 100644
--- a/src/Rust/vvs_utils/src/file/temp.rs
+++ b/src/Rust/vvs_xdg/src/file/temp.rs
@@ -1,11 +1,12 @@
-use crate::xdg::*;
+use crate::*;
 use std::{
-    fs::{File, OpenOptions},
+    fs::{self, File, OpenOptions},
     io::Error as IoError,
     ops::{Deref, DerefMut},
-    path::PathBuf,
+    path::{Path, PathBuf},
 };
 use thiserror::Error;
+use vvs_utils::rand;
 
 /// An error can be comming from the IO thing or we have a collision with the temp file name.
 #[derive(Debug, Error)]
@@ -27,21 +28,37 @@ pub enum TempError {
 pub type TempResult<T> = Result<T, TempError>;
 
 /// The temporary file structure.
-pub struct TempFile(File);
+pub struct TempFile {
+    file: File,
+    path: PathBuf,
+    leak: bool,
+}
 
 impl Deref for TempFile {
     type Target = File;
 
     #[inline]
     fn deref(&self) -> &Self::Target {
-        &self.0
+        &self.file
     }
 }
 
 impl DerefMut for TempFile {
     #[inline]
     fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.0
+        &mut self.file
+    }
+}
+
+impl Drop for TempFile {
+    fn drop(&mut self) {
+        if !self.leak {
+            if let Err(err) = fs::remove_file(&self.path) {
+                log::error!("failed to delete temp file '{}': {err}", self.path.display())
+            }
+        } else {
+            log::debug!("leak temp file '{}'", self.path.display());
+        }
     }
 }
 
@@ -102,13 +119,27 @@ impl TempFile {
     /// reused between reboots, and that temp folder are cleared at reboots...
     #[inline]
     pub fn new(app: impl AsRef<str>) -> TempResult<Self> {
-        let (pid, rand) = (std::process::id(), crate::rand());
+        let (pid, rand) = (std::process::id(), rand());
+        let path = Self::create(app, format!("tmp.{pid}.{rand}"))?;
         let file = OpenOptions::new()
             .create_new(true)
             .write(true)
             .read(true)
-            .open(Self::create(app, format!("tmp.{pid}.{rand}"))?)
+            .open(&path)
             .map_err(Self::handle_io_error)?;
-        Ok(Self(file))
+        Ok(Self { file, path, leak: false })
+    }
+
+    /// Allow to leak the file, it will still exists after the application finished to run.
+    #[inline]
+    pub fn leak(mut self) -> Self {
+        self.leak = true;
+        self
+    }
+
+    /// Get the path of the temp file.
+    #[inline]
+    pub fn path(&self) -> &Path {
+        &self.path
     }
 }
diff --git a/src/Rust/vvs_utils/src/xdg/folders.rs b/src/Rust/vvs_xdg/src/folders.rs
similarity index 98%
rename from src/Rust/vvs_utils/src/xdg/folders.rs
rename to src/Rust/vvs_xdg/src/folders.rs
index 3933ddb5..4f7364b9 100644
--- a/src/Rust/vvs_utils/src/xdg/folders.rs
+++ b/src/Rust/vvs_xdg/src/folders.rs
@@ -1,9 +1,6 @@
 //! The main provider for resolving files with the XDG specification + some utilities.
 
-use crate::{
-    either,
-    xdg::{MaybeFolderList, XDGError, XDGFindBehaviour},
-};
+use crate::{MaybeFolderList, XDGError, XDGFindBehaviour};
 use std::{io::ErrorKind as IoErrorKind, path::PathBuf};
 
 /// The type of folder we want. Here are some remarks from the specification about file resolution:
@@ -128,7 +125,7 @@ impl XDGFolder {
             }
         }
 
-        let home = crate::xdg::home_folder();
+        let home = crate::home_folder();
         match std::env::var(self.env_var_name()) {
             Ok(folder_list) if self.is_list() => MaybeFolderList::from_str_list(&folder_list, Self::SEPARATOR),
             Ok(folder) => MaybeFolderList::Folder(PathBuf::from(folder)),
@@ -200,7 +197,7 @@ impl XDGFolder {
                 }
             }
             let path = path.join(file.as_ref());
-            Some(either!(path.exists() => FindState::Exists(path); FindState::CanCreate(path)))
+            Some(if path.exists() { FindState::Exists(path) } else { FindState::CanCreate(path) })
         })
         .collect();
 
diff --git a/src/Rust/vvs_utils/src/xdg/mod.rs b/src/Rust/vvs_xdg/src/lib.rs
similarity index 98%
rename from src/Rust/vvs_utils/src/xdg/mod.rs
rename to src/Rust/vvs_xdg/src/lib.rs
index 8435840a..9183ddf8 100644
--- a/src/Rust/vvs_utils/src/xdg/mod.rs
+++ b/src/Rust/vvs_xdg/src/lib.rs
@@ -1,6 +1,8 @@
 //! Utility functions to follow the freedesktop specifications on config folders and such:
 //! https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
 
+pub mod file;
+
 #[cfg(test)]
 mod tests;
 
diff --git a/src/Rust/vvs_utils/src/xdg/options.rs b/src/Rust/vvs_xdg/src/options.rs
similarity index 100%
rename from src/Rust/vvs_utils/src/xdg/options.rs
rename to src/Rust/vvs_xdg/src/options.rs
diff --git a/src/Rust/vvs_utils/src/xdg/paths.rs b/src/Rust/vvs_xdg/src/paths.rs
similarity index 100%
rename from src/Rust/vvs_utils/src/xdg/paths.rs
rename to src/Rust/vvs_xdg/src/paths.rs
diff --git a/src/Rust/vvs_utils/src/xdg/tests.rs b/src/Rust/vvs_xdg/src/tests.rs
similarity index 100%
rename from src/Rust/vvs_utils/src/xdg/tests.rs
rename to src/Rust/vvs_xdg/src/tests.rs
diff --git a/src/Rust/vvs_utils/src/xdg/traits.rs b/src/Rust/vvs_xdg/src/traits.rs
similarity index 100%
rename from src/Rust/vvs_utils/src/xdg/traits.rs
rename to src/Rust/vvs_xdg/src/traits.rs
-- 
GitLab