1mod execution;
4mod model;
5mod protocol;
6mod repository;
7mod sandbox;
8
9use std::fmt;
10use std::path::{Path, PathBuf};
11use std::sync::Arc;
12
13pub use model::{
14 Error, File, ObjectStoreError, ObjectStoreResult, Result, RunRequest, RunResult, RustBinInput,
15 RustBinOutput,
16};
17use model::{ValidSource, validate_name, validate_source};
18pub use protocol::{read_input, write_output};
19
20pub trait ObjectStore: Send + Sync {
22 fn load(&self, object_id: &str) -> ObjectStoreResult<Vec<u8>>;
23 fn save(&self, bytes: &[u8]) -> ObjectStoreResult<String>;
24}
25
26pub struct Lib {
28 pub files: Vec<File>,
30 repository: PathBuf,
31 name: String,
32 identity: String,
33 object_store: Arc<dyn ObjectStore>,
34}
35
36pub fn create(
38 rust_bins_root: impl AsRef<Path>,
39 name: &str,
40 object_store: Arc<dyn ObjectStore>,
41) -> Result<Lib> {
42 validate_name(name)?;
43 let source = initial_source(name)?;
44 let snapshot = repository::create(rust_bins_root.as_ref(), name, &source)?;
45 Ok(Lib {
46 files: snapshot.files,
47 repository: snapshot.repository,
48 name: name.to_owned(),
49 identity: snapshot.identity,
50 object_store,
51 })
52}
53
54pub fn open(
56 rust_bins_root: impl AsRef<Path>,
57 name: &str,
58 object_store: Arc<dyn ObjectStore>,
59) -> Result<Lib> {
60 validate_name(name)?;
61 let snapshot = repository::open(rust_bins_root.as_ref(), name)?;
62 Ok(Lib {
63 files: snapshot.files,
64 repository: snapshot.repository,
65 name: name.to_owned(),
66 identity: snapshot.identity,
67 object_store,
68 })
69}
70
71pub fn docs(rust_bins_root: impl AsRef<Path>, name: &str) -> Result<(String, String)> {
73 validate_name(name)?;
74 repository::docs(rust_bins_root.as_ref(), name)
75}
76
77pub fn run(
79 object_store: &dyn ObjectStore,
80 binary_object_id: &str,
81 request: &RunRequest,
82) -> Result<RunResult> {
83 execution::run(object_store, binary_object_id, request)
84}
85
86impl Lib {
87 pub fn write(&mut self) -> Result<()> {
89 let source = validate_source(&self.files, &self.name)?;
90 let snapshot = repository::replace(&self.repository, &self.identity, &source)?;
91 self.files = snapshot.files;
92 self.identity = snapshot.identity;
93 Ok(())
94 }
95
96 pub fn check(&self) -> Result<()> {
98 let source = validate_source(&self.files, &self.name)?;
99 sandbox::check(&source, &self.name)
100 }
101
102 pub fn publish(&self) -> Result<String> {
104 let source = validate_source(&self.files, &self.name)?;
105 let executable = sandbox::build(&source, &self.name)?;
106 self.object_store
107 .save(&executable)
108 .map_err(|error| Error::object_store("save executable", None, error))
109 }
110}
111
112impl fmt::Debug for Lib {
113 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
114 formatter
115 .debug_struct("Lib")
116 .field("files", &self.files)
117 .field("repository", &self.repository)
118 .field("name", &self.name)
119 .field("identity", &"[PRIVATE]")
120 .field("object_store", &"[PRIVATE]")
121 .finish()
122 }
123}
124
125fn initial_source(name: &str) -> Result<ValidSource> {
126 validate_source(
127 &[
128 File {
129 path: "Cargo.toml".to_owned(),
130 contents: format!(
131 "[package]\nname = \"{name}\"\nversion = \"0.1.0\"\nedition = \"2024\"\n\n[dependencies]\n"
132 ),
133 },
134 File {
135 path: "Documentation.md".to_owned(),
136 contents: String::new(),
137 },
138 File {
139 path: "src/main.rs".to_owned(),
140 contents: "fn main() {}\n".to_owned(),
141 },
142 ],
143 name,
144 )
145}