1pub mod multi_target;
2
3use crate::ast::*;
4use crate::transform::TransformCtx;
5use serde::{Deserialize, Deserializer, Serialize};
6use serde_state::{DeserializeState, SerializeState};
7use std::fs::File;
8use std::path::Path;
9
10#[derive(SerializeState, DeserializeState)]
13pub struct CrateData {
14 #[serde_state(stateless)]
17 pub charon_version: CharonVersion,
18 pub translated: TranslatedCrate,
19 #[serde_state(stateless)]
20 #[charon::opaque] pub has_errors: bool,
23}
24
25impl Serialize for CrateData {
26 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27 where
28 S: serde::Serializer,
29 {
30 if self.translated.options.no_dedup_serialized_ast {
31 self.serialize_state(&(), serializer)
32 } else {
33 let state = HashConsDedupSerializer::default();
34 self.serialize_state(&state, serializer)
35 }
36 }
37}
38
39impl<'de> Deserialize<'de> for CrateData {
40 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
41 where
42 D: Deserializer<'de>,
43 {
44 let state = HashConsDedupSerializer::default();
46 Self::deserialize_state(&state, deserializer)
47 }
48}
49
50#[derive(Serialize)]
51pub struct CharonVersion(pub String);
52
53impl<'de> Deserialize<'de> for CharonVersion {
54 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
55 where
56 D: Deserializer<'de>,
57 {
58 use serde::de::Error;
59 let version = String::deserialize(deserializer)?;
60 if version != crate::VERSION {
61 return Err(D::Error::custom(format!(
62 "Incompatible version of charon: \
63 this program supports llbc emitted by charon v{} \
64 but attempted to read a file emitted by charon v{}",
65 crate::VERSION,
66 version,
67 )));
68 }
69 Ok(CharonVersion(version))
70 }
71}
72
73impl CrateData {
74 pub fn new(ctx: TransformCtx) -> Self {
75 CrateData {
76 charon_version: CharonVersion(crate::VERSION.to_owned()),
77 has_errors: ctx.has_errors(),
78 translated: ctx.translated,
79 }
80 }
81
82 #[allow(clippy::result_unit_err)]
84 pub fn serialize_to_file(&self, target_filename: &Path) -> Result<(), ()> {
85 let target_dir = target_filename.parent().unwrap();
89 match std::fs::create_dir_all(target_dir) {
90 Ok(()) => (),
91 Err(_) => {
92 error!("Could not create the directory: {:?}", target_dir);
93 return Err(());
94 }
95 };
96
97 let std::io::Result::Ok(outfile) = File::create(target_filename) else {
99 error!("Could not open: {:?}", target_filename);
100 return Err(());
101 };
102 let res = serde_json::to_writer(&outfile, self);
104 match res {
105 Ok(()) => {}
106 Err(err) => {
107 error!("Could not serialize to `{target_filename:?}`: {err:?}");
108 return Err(());
109 }
110 }
111
112 let target_filename = std::fs::canonicalize(target_filename).unwrap();
115 if self.has_errors {
116 info!(
117 "Generated the partial (because we encountered errors) file: {}",
118 target_filename.to_str().unwrap()
119 );
120 } else {
121 info!("Generated the file: {}", target_filename.to_str().unwrap());
122 }
123 Ok(())
124 }
125
126 pub fn deserialize_from_file(path: &std::path::Path) -> anyhow::Result<Self> {
127 use crate::export::CrateData;
128 use anyhow::Context;
129 use serde::Deserialize;
130 use std::fs::File;
131 use std::io::BufReader;
132 let file = File::open(path)
133 .with_context(|| format!("Failed to read llbc file {}", path.display()))?;
134 let reader = BufReader::new(file);
135 let mut deserializer = serde_json::Deserializer::from_reader(reader);
136 deserializer.disable_recursion_limit();
138 let deserializer = serde_stacker::Deserializer::new(&mut deserializer);
140 Ok(CrateData::deserialize(deserializer)?)
141 }
142}