use std::error::Error; use std::fmt; use std::fs::File as FsFile; use std::io; use std::io::{Read, Write}; use std::ops::Deref; use std::path::Path; use resources::Resource; use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner}; pub struct File where C: Deref, D: AsRef, { path: D, content: C, } impl File where C: Deref, D: AsRef, { pub fn new(path: D, content: C) -> Self { File { path, content } } } impl Symbol for File where C: Deref, D: AsRef, { fn target_reached(&self) -> Result> { let file = FsFile::open(self.path.as_ref()); // Check if file exists if let Err(e) = file { return if e.kind() == io::ErrorKind::NotFound { Ok(false) } else { Err(Box::new(e)) }; } // Check if content is the same let mut file_content = file.unwrap().bytes(); let mut target_content = self.content.bytes(); loop { match (file_content.next(), target_content.next()) { (None, None) => return Ok(true), (Some(Ok(a)), Some(b)) if a == b => {} (Some(Err(e)), _) => return Err(Box::new(e)), (_, _) => return Ok(false), } } } fn execute(&self) -> Result<(), Box> { let mut file = FsFile::create(self.path.as_ref())?; file.write_all(self.content.as_bytes())?; Ok(()) } fn get_prerequisites(&self) -> Vec { vec![Resource::new( "dir", Path::new(self.path.as_ref()) .parent() .unwrap() .to_string_lossy(), )] } fn as_action<'a>(&'a self, runner: &'a dyn SymbolRunner) -> Box { Box::new(SymbolAction::new(runner, self)) } fn into_action<'a>(self: Box, runner: &'a dyn SymbolRunner) -> Box where Self: 'a, { Box::new(OwnedSymbolAction::new(runner, *self)) } } impl fmt::Display for File where C: Deref, D: AsRef, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "File {}", self.path.as_ref().display()) } }