custom_sink/
custom_sink.rs1#[path = "support/objects.rs"]
15mod objects;
16
17use std::sync::Mutex;
18use std::sync::atomic::{AtomicUsize, Ordering};
19
20use qld::args::{InputAttrs, InputKind, LinkOptions, OutputBuffer, OutputKind};
21use qld::diag::{Diagnostic, DiagnosticSink, Severity};
22
23#[derive(Default)]
25struct JsonLines {
26 diagnostics: Mutex<Vec<Diagnostic>>,
27 errors: AtomicUsize,
28}
29
30impl DiagnosticSink for JsonLines {
31 fn emit(&self, diagnostic: Diagnostic) {
32 if diagnostic.severity == Severity::Error {
33 self.errors.fetch_add(1, Ordering::Relaxed);
34 }
35 if let Ok(mut diagnostics) = self.diagnostics.lock() {
36 diagnostics.push(diagnostic);
37 }
38 }
39
40 fn error_count(&self) -> usize {
41 self.errors.load(Ordering::Relaxed)
42 }
43}
44
45impl JsonLines {
46 fn render(&self) -> String {
49 let mut diagnostics = match self.diagnostics.lock() {
50 Ok(mut diagnostics) => std::mem::take(&mut *diagnostics),
51 Err(_) => return String::new(),
52 };
53 diagnostics.sort_by(|a, b| a.order.cmp(&b.order).then(a.message.cmp(&b.message)));
54 let mut out = String::new();
55 for diagnostic in diagnostics {
56 let locations: Vec<String> = diagnostic
57 .locations
58 .iter()
59 .map(|location| quote(&location.to_string()))
60 .collect();
61 let details: Vec<String> = diagnostic.details.iter().map(|d| quote(d)).collect();
62 out.push_str(&format!(
63 "{{\"severity\":{},\"message\":{},\"locations\":[{}],\"details\":[{}]}}\n",
64 quote(&diagnostic.severity.to_string()),
65 quote(&diagnostic.message),
66 locations.join(","),
67 details.join(","),
68 ));
69 }
70 out
71 }
72}
73
74fn quote(text: &str) -> String {
76 let mut out = String::from('"');
77 for c in text.chars() {
78 match c {
79 '"' => out.push_str("\\\""),
80 '\\' => out.push_str("\\\\"),
81 c if u32::from(c) < 0x20 => out.push_str(&format!("\\u{:04x}", u32::from(c))),
82 c => out.push(c),
83 }
84 }
85 out.push('"');
86 out
87}
88
89fn main() {
90 let mut options = LinkOptions::new();
92 options.kind = OutputKind::StaticExecutable;
93 options.output_buffer = Some(OutputBuffer::new());
94 options.push_input(
95 InputKind::bytes("main.o", objects::main_object()),
96 InputAttrs::default(),
97 );
98
99 let sink = JsonLines::default();
100 let result = qld::link(&options, &sink);
101 print!("{}", sink.render());
102 match result {
103 Ok(()) => println!("linked"),
104 Err(qld::Error::Reported { errors }) => {
105 println!("the link failed with {errors} error(s) reported above");
106 }
107 Err(error) => println!("the link failed: {error}"),
108 }
109}