uqa_analysis/analyzer/
diagnostics.rs1use std::io::{self, Write};
10
11use serde::Serialize;
12use uqa_core::memory::{Budgeted, BudgetedVec, MemoryBudget};
13
14use crate::{AnalysisError, AnalysisResult, AnalyzedText, AnalyzerFingerprint, CompiledAnalyzer};
15
16#[derive(Serialize)]
17struct Diagnostic<'a> {
18 #[serde(flatten)]
19 analysis: &'a AnalyzedText,
20 analyzer_fingerprint: &'a AnalyzerFingerprint,
21}
22
23impl CompiledAnalyzer {
24 pub fn analyze_diagnostic_budgeted(
28 &self,
29 text: &str,
30 budget: &MemoryBudget,
31 mut poll: impl FnMut() -> AnalysisResult<()>,
32 ) -> AnalysisResult<Budgeted<String>> {
33 let analysis = self.analyze_tokens_budgeted(text, budget, &mut poll)?;
34 let diagnostic = Diagnostic {
35 analysis: &analysis,
36 analyzer_fingerprint: &self.descriptor().fingerprint(),
37 };
38 let mut writer = DiagnosticWriter {
39 bytes: BudgetedVec::new(budget),
40 poll: &mut poll,
41 failure: None,
42 };
43 let result = serde_json::to_writer(&mut writer, &diagnostic);
44 if let Some(error) = writer.failure {
45 return Err(error);
46 }
47 result?;
48 (writer.poll)()?;
49 drop(analysis);
50 let (bytes, memory) = writer.bytes.into_parts();
51 let json = String::from_utf8(bytes).expect("JSON serialization emits valid UTF-8");
52 Ok(Budgeted::new(json, memory))
53 }
54}
55
56struct DiagnosticWriter<'a> {
57 bytes: BudgetedVec<u8>,
58 poll: &'a mut dyn FnMut() -> AnalysisResult<()>,
59 failure: Option<AnalysisError>,
60}
61
62impl Write for DiagnosticWriter<'_> {
63 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
64 let result = (self.poll)().and_then(|()| {
65 self.bytes.extend_from_slice(bytes)?;
66 Ok(())
67 });
68 if let Err(error) = result {
69 self.failure = Some(error);
70 return Err(io::Error::other("analysis diagnostic encoding interrupted"));
71 }
72 Ok(bytes.len())
73 }
74
75 fn flush(&mut self) -> io::Result<()> {
76 Ok(())
77 }
78}
79
80#[cfg(test)]
81mod tests;