1use std::path::Path;
14
15use serde::{Deserialize, Serialize};
16
17use crate::Config;
18use crate::loader::{self, LoadError};
19
20pub const FORMAT_VERSION: u8 = 1;
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct Compiled {
29 pub format_version: u8,
31 pub flusso_version: String,
33 pub config: Config,
35}
36
37#[derive(thiserror::Error, Debug)]
38pub enum CompileError {
39 #[error(transparent)]
40 Load(#[from] LoadError),
41 #[error("failed to read compiled config `{path}`: {source}")]
42 Read {
43 path: std::path::PathBuf,
44 #[source]
45 source: std::io::Error,
46 },
47 #[error("failed to write compiled config `{path}`: {source}")]
48 Write {
49 path: std::path::PathBuf,
50 #[source]
51 source: std::io::Error,
52 },
53 #[error("failed to encode compiled config: {0}")]
54 Encode(#[from] rmp_serde::encode::Error),
55 #[error("failed to decode compiled config: {0}")]
56 Decode(#[from] rmp_serde::decode::Error),
57 #[error(
58 "compiled config format version {got} is not supported by this build \
59 (expected {expected}); recompile with a matching `flusso`"
60 )]
61 VersionMismatch { got: u8, expected: u8 },
62}
63
64pub fn compile(config_path: impl AsRef<Path>) -> Result<Compiled, CompileError> {
68 let config = loader::load(config_path)?;
69 Ok(Compiled {
70 format_version: FORMAT_VERSION,
71 flusso_version: env!("CARGO_PKG_VERSION").to_owned(),
72 config,
73 })
74}
75
76pub fn to_bytes(compiled: &Compiled) -> Result<Vec<u8>, CompileError> {
78 Ok(rmp_serde::to_vec_named(compiled)?)
79}
80
81pub fn write(compiled: &Compiled, path: impl AsRef<Path>) -> Result<(), CompileError> {
83 let path = path.as_ref();
84 let bytes = to_bytes(compiled)?;
85 std::fs::write(path, bytes).map_err(|source| CompileError::Write {
86 path: path.to_path_buf(),
87 source,
88 })
89}
90
91pub fn from_bytes(bytes: &[u8]) -> Result<Config, CompileError> {
94 let compiled: Compiled = rmp_serde::from_slice(bytes)?;
95 if compiled.format_version != FORMAT_VERSION {
96 return Err(CompileError::VersionMismatch {
97 got: compiled.format_version,
98 expected: FORMAT_VERSION,
99 });
100 }
101 Ok(compiled.config)
102}
103
104pub fn load_compiled(path: impl AsRef<Path>) -> Result<Config, CompileError> {
106 let path = path.as_ref();
107 let bytes = std::fs::read(path).map_err(|source| CompileError::Read {
108 path: path.to_path_buf(),
109 source,
110 })?;
111 from_bytes(&bytes)
112}