ruby_prism/parse_result/
diagnostics.rs1use std::ffi::{c_char, CStr};
4use std::marker::PhantomData;
5use std::ptr::NonNull;
6
7use ruby_prism_sys::{pm_diagnostic_t, pm_parser_t};
8
9use super::Location;
10
11#[derive(Debug)]
13pub struct Diagnostic<'pr> {
14 diag: NonNull<pm_diagnostic_t>,
15 parser: NonNull<pm_parser_t>,
16 marker: PhantomData<&'pr pm_diagnostic_t>,
17}
18
19impl<'pr> Diagnostic<'pr> {
20 #[must_use]
27 pub fn message(&self) -> &str {
28 unsafe {
29 let message: *mut c_char = self.diag.as_ref().message.cast_mut();
30 CStr::from_ptr(message).to_str().expect("prism allows only UTF-8 for diagnostics.")
31 }
32 }
33
34 #[must_use]
36 pub const fn location(&self) -> Location<'pr> {
37 Location::new(self.parser, unsafe { &self.diag.as_ref().location })
38 }
39}
40
41pub struct Diagnostics<'pr> {
44 diagnostic: *mut pm_diagnostic_t,
45 parser: NonNull<pm_parser_t>,
46 marker: PhantomData<&'pr pm_diagnostic_t>,
47}
48
49impl Diagnostics<'_> {
50 pub(crate) const fn new(diagnostic: *mut pm_diagnostic_t, parser: NonNull<pm_parser_t>) -> Self {
51 Diagnostics { diagnostic, parser, marker: PhantomData }
52 }
53}
54
55impl<'pr> Iterator for Diagnostics<'pr> {
56 type Item = Diagnostic<'pr>;
57
58 fn next(&mut self) -> Option<Self::Item> {
59 if let Some(diagnostic) = NonNull::new(self.diagnostic) {
60 let current = Diagnostic {
61 diag: diagnostic,
62 parser: self.parser,
63 marker: PhantomData,
64 };
65 self.diagnostic = unsafe { diagnostic.as_ref().node.next.cast::<pm_diagnostic_t>() };
66 Some(current)
67 } else {
68 None
69 }
70 }
71}