use crate::ast::*;
use crate::transform::TransformCtx;
use serde::{Deserialize, Deserializer, Serialize};
use std::fs::File;
use std::path::Path;
#[derive(Serialize, Deserialize)]
#[serde(rename = "Crate")]
pub struct CrateData {
#[serde(deserialize_with = "ensure_version")]
pub charon_version: String,
pub translated: TranslatedCrate,
#[serde(skip)]
pub has_errors: bool,
}
impl CrateData {
pub fn new(ctx: &TransformCtx) -> Self {
CrateData {
charon_version: crate::VERSION.to_owned(),
translated: ctx.translated.clone(),
has_errors: ctx.has_errors(),
}
}
#[allow(clippy::result_unit_err)]
pub fn serialize_to_file(&self, target_filename: &Path) -> Result<(), ()> {
let target_dir = target_filename.parent().unwrap();
match std::fs::create_dir_all(target_dir) {
Ok(()) => (),
Err(_) => {
error!("Could not create the directory: {:?}", target_dir);
return Err(());
}
};
let std::io::Result::Ok(outfile) = File::create(target_filename) else {
error!("Could not open: {:?}", target_filename);
return Err(());
};
match serde_json::to_writer(&outfile, self) {
Ok(()) => {}
Err(err) => {
error!("Could not write to `{target_filename:?}`: {err:?}");
return Err(());
}
}
let target_filename = std::fs::canonicalize(target_filename).unwrap();
if self.has_errors {
info!(
"Generated the partial (because we encountered errors) file: {}",
target_filename.to_str().unwrap()
);
} else {
info!("Generated the file: {}", target_filename.to_str().unwrap());
}
Ok(())
}
}
fn ensure_version<'de, D: Deserializer<'de>>(d: D) -> Result<String, D::Error> {
use serde::de::Error;
let version = String::deserialize(d)?;
if version != crate::VERSION {
return Err(D::Error::custom(format!(
"Incompatible version of charon: \
this program supports llbc emitted by charon v{} \
but attempted to read a file emitted by charon v{}",
crate::VERSION,
version,
)));
}
Ok(version)
}