1mod execution;
4mod model;
5mod protocol;
6mod publication;
7mod repository;
8mod sandbox;
9
10use std::fmt;
11use std::path::{Path, PathBuf};
12use std::time::Duration;
13
14pub use model::{
15 Error, File, ObjectStoreError, ObjectStoreResult, Result, RunRequest, RunResult, RustBinInput,
16 RustBinOutput,
17};
18use model::{ValidSource, validate_name, validate_source};
19pub use protocol::{read_input, write_output};
20
21pub trait ObjectStore: Send + Sync {
26 fn load(&self, object_id: &str) -> ObjectStoreResult<Vec<u8>>;
27 fn save(&self, bytes: &[u8]) -> ObjectStoreResult<String>;
28}
29
30pub const DEFAULT_RUN_TIMEOUT: Duration = Duration::from_secs(2 * 60);
32
33pub struct Lib {
35 pub files: Vec<File>,
37 repository: PathBuf,
38 name: String,
39 identity: String,
40 publications: PathBuf,
41}
42
43pub fn create(
45 rust_bins_root: impl AsRef<Path>,
46 publications_root: impl AsRef<Path>,
47 name: &str,
48) -> Result<Lib> {
49 validate_name(name)?;
50 let source = initial_source(name)?;
51 let snapshot = repository::create(rust_bins_root.as_ref(), name, &source)?;
52 Ok(Lib {
53 files: snapshot.files,
54 repository: snapshot.repository,
55 name: name.to_owned(),
56 identity: snapshot.identity,
57 publications: publications_root.as_ref().to_path_buf(),
58 })
59}
60
61pub fn open(
63 rust_bins_root: impl AsRef<Path>,
64 publications_root: impl AsRef<Path>,
65 name: &str,
66) -> Result<Lib> {
67 validate_name(name)?;
68 let snapshot = repository::open(rust_bins_root.as_ref(), name)?;
69 Ok(Lib {
70 files: snapshot.files,
71 repository: snapshot.repository,
72 name: name.to_owned(),
73 identity: snapshot.identity,
74 publications: publications_root.as_ref().to_path_buf(),
75 })
76}
77
78pub fn docs(rust_bins_root: impl AsRef<Path>, name: &str) -> Result<(String, String)> {
80 validate_name(name)?;
81 repository::docs(rust_bins_root.as_ref(), name)
82}
83
84pub fn run(
90 publications_root: impl AsRef<Path>,
91 object_store: &dyn ObjectStore,
92 name: &str,
93 version_selector: &str,
94 request: &RunRequest,
95 timeout: Option<Duration>,
96) -> Result<RunResult> {
97 validate_name(name)?;
98 let publication = publication::resolve(publications_root.as_ref(), name, version_selector)?;
99 execution::run(
100 object_store,
101 &publication.executable,
102 publication.version.to_string(),
103 request,
104 timeout.unwrap_or(DEFAULT_RUN_TIMEOUT),
105 )
106}
107
108impl Lib {
109 pub fn write(&mut self) -> Result<()> {
111 let source = validate_source(&self.files, &self.name)?;
112 let snapshot = repository::replace(&self.repository, &self.identity, &source)?;
113 self.files = snapshot.files;
114 self.identity = snapshot.identity;
115 Ok(())
116 }
117
118 pub fn check(&self) -> Result<()> {
120 let source = validate_source(&self.files, &self.name)?;
121 sandbox::check(&source, &self.name)
122 }
123
124 pub fn publish(&self) -> Result<()> {
126 let source = validate_source(&self.files, &self.name)?;
127 let executable = sandbox::build(&source, &self.name)?;
128 publication::publish(&self.publications, &self.name, &source.version, &executable)
129 }
130}
131
132impl fmt::Debug for Lib {
133 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
134 formatter
135 .debug_struct("Lib")
136 .field("files", &self.files)
137 .field("repository", &self.repository)
138 .field("name", &self.name)
139 .field("identity", &"[PRIVATE]")
140 .field("publications", &self.publications)
141 .finish()
142 }
143}
144
145fn initial_source(name: &str) -> Result<ValidSource> {
146 validate_source(
147 &[
148 File {
149 path: "Cargo.toml".to_owned(),
150 contents: format!(
151 "[package]\nname = \"{name}\"\nversion = \"0.1.0\"\nedition = \"2024\"\n\n[dependencies]\n"
152 ),
153 },
154 File {
155 path: "Documentation.md".to_owned(),
156 contents: String::new(),
157 },
158 File {
159 path: "src/main.rs".to_owned(),
160 contents: "fn main() {}\n".to_owned(),
161 },
162 ],
163 name,
164 )
165}