use crate::Forge;
use std::path::Path;
pub struct Either<L: Forge, R: Forge> {
left: L,
right: R,
}
impl<L: Forge, R: Forge> Forge for Either<L, R> {
type Error = R::Error;
fn forge(&self, into: impl AsRef<Path>) -> Result<(), Self::Error> {
self.left.forge(&into).or_else(|_| self.right.forge(&into))
}
}
impl<L: Forge, R: Forge> Either<L, R> {
pub fn new(left: L, right: R) -> Self {
Self { left, right }
}
}
#[inline]
pub fn either<L: Forge, R: Forge>(left: L, right: R) -> Either<L, R> {
Either::new(left, right)
}
#[cfg(test)]
mod tests {
use super::*;
use std::io;
use std::path::PathBuf;
use tempfile::tempdir;
struct MockForge<F>
where
F: Fn() -> Result<(), io::Error>,
{
action: F,
}
impl<F> Forge for MockForge<F>
where
F: Fn() -> Result<(), io::Error>,
{
type Error = io::Error;
fn forge(&self, _into: impl AsRef<Path>) -> Result<(), Self::Error> {
(self.action)()
}
}
#[test]
fn test_either_uses_left_when_successful() {
let temp_dir = tempdir().unwrap();
let test_path = temp_dir.path().join("test.txt");
let left = MockForge { action: || Ok(()) };
let right = MockForge {
action: || {
Err(io::Error::new(
io::ErrorKind::Other,
"Right should not be called",
))
},
};
let either_forge = either(left, right);
let result = either_forge.forge(&test_path);
assert!(result.is_ok());
}
#[test]
fn test_either_uses_right_when_left_fails() {
let temp_dir = tempdir().unwrap();
let test_path = temp_dir.path().join("test.txt");
let left = MockForge {
action: || Err(io::Error::new(io::ErrorKind::Other, "Left fails")),
};
let right = MockForge { action: || Ok(()) };
let either_forge = either(left, right);
let result = either_forge.forge(&test_path);
assert!(result.is_ok());
}
#[test]
fn test_either_fails_when_both_fail() {
let temp_dir = tempdir().unwrap();
let test_path = temp_dir.path().join("test.txt");
let left = MockForge {
action: || Err(io::Error::new(io::ErrorKind::Other, "Left fails")),
};
let right_error = "Right fails too";
let right = MockForge {
action: move || Err(io::Error::new(io::ErrorKind::Other, right_error)),
};
let either_forge = either(left, right);
let result = either_forge.forge(&test_path);
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), right_error);
}
#[test]
fn test_either_convenience_function() {
let left = MockForge { action: || Ok(()) };
let right = MockForge { action: || Ok(()) };
let either_forge = either(left, right);
let test_path = PathBuf::from("/tmp/test.txt"); let result = either_forge.forge(test_path);
assert!(result.is_ok());
}
}