use std::future::Future;
use std::path::Path;
use std::pin::Pin;
use anyclaw_sdk_types::WorkspaceScope;
use crate::error::ToolSdkError;
pub trait WorkspaceExec: Send + Sync + 'static {
fn scope(&self) -> WorkspaceScope;
fn read_file(&self, path: &Path) -> impl Future<Output = Result<Vec<u8>, ToolSdkError>> + Send;
fn write_file(
&self,
path: &Path,
contents: &[u8],
) -> impl Future<Output = Result<(), ToolSdkError>> + Send;
fn exec(
&self,
command: &str,
args: &[&str],
) -> impl Future<Output = Result<ExecOutput, ToolSdkError>> + Send;
}
pub trait DynWorkspaceExec: Send + Sync + 'static {
fn scope(&self) -> WorkspaceScope;
fn read_file<'a>(
&'a self,
path: &'a Path,
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, ToolSdkError>> + Send + 'a>>;
fn write_file<'a>(
&'a self,
path: &'a Path,
contents: &'a [u8],
) -> Pin<Box<dyn Future<Output = Result<(), ToolSdkError>> + Send + 'a>>;
fn exec<'a>(
&'a self,
command: &'a str,
args: &'a [&'a str],
) -> Pin<Box<dyn Future<Output = Result<ExecOutput, ToolSdkError>> + Send + 'a>>;
}
impl<T: WorkspaceExec> DynWorkspaceExec for T {
fn scope(&self) -> WorkspaceScope {
WorkspaceExec::scope(self)
}
fn read_file<'a>(
&'a self,
path: &'a Path,
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, ToolSdkError>> + Send + 'a>> {
Box::pin(WorkspaceExec::read_file(self, path))
}
fn write_file<'a>(
&'a self,
path: &'a Path,
contents: &'a [u8],
) -> Pin<Box<dyn Future<Output = Result<(), ToolSdkError>> + Send + 'a>> {
Box::pin(WorkspaceExec::write_file(self, path, contents))
}
fn exec<'a>(
&'a self,
command: &'a str,
args: &'a [&'a str],
) -> Pin<Box<dyn Future<Output = Result<ExecOutput, ToolSdkError>> + Send + 'a>> {
Box::pin(WorkspaceExec::exec(self, command, args))
}
}
#[derive(Debug, Clone)]
pub struct ExecOutput {
pub exit_code: i32,
pub stdout: Vec<u8>,
pub stderr: Vec<u8>,
}
impl ExecOutput {
pub fn success(&self) -> bool {
self.exit_code == 0
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
fn when_exec_output_exit_zero_then_success() {
let output = ExecOutput {
exit_code: 0,
stdout: vec![],
stderr: vec![],
};
assert!(output.success());
}
#[rstest]
fn when_exec_output_exit_nonzero_then_not_success() {
let output = ExecOutput {
exit_code: 1,
stdout: vec![],
stderr: b"error".to_vec(),
};
assert!(!output.success());
}
#[rstest]
fn when_dyn_workspace_exec_used_as_trait_object_then_compiles() {
fn _accepts_dyn(_w: &dyn DynWorkspaceExec) {}
}
}