From 9ebc3130272e2d5c3b85065985af05f6079e2f42 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Mon, 4 Aug 2025 23:23:35 +0200 Subject: [PATCH] Some fancy error --- Cargo.lock | 33 ++++- ray-tracing-pbrt-scene/Cargo.toml | 1 + ray-tracing-pbrt-scene/example.pbrt | 1 + ray-tracing-pbrt-scene/src/lib.rs | 216 +++++++++++++++++++++++----- 4 files changed, 206 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4788244..1cd8b5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -373,7 +373,7 @@ dependencies = [ "log", "nix 0.25.1", "slotmap", - "thiserror", + "thiserror 1.0.69", "vec_map", ] @@ -1328,7 +1328,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -1586,7 +1586,7 @@ dependencies = [ "ndk-sys", "num_enum 0.5.11", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2204,7 +2204,7 @@ dependencies = [ "rand_chacha", "simd_helpers", "system-deps", - "thiserror", + "thiserror 1.0.69", "v_frame", "wasm-bindgen", ] @@ -2293,6 +2293,7 @@ dependencies = [ "miette", "nom 8.0.0", "ray-tracing-core", + "thiserror 2.0.12", ] [[package]] @@ -2373,7 +2374,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2757,7 +2758,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -2771,6 +2781,17 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "thread_local" version = "1.1.8" diff --git a/ray-tracing-pbrt-scene/Cargo.toml b/ray-tracing-pbrt-scene/Cargo.toml index e3ecbf3..c16fc8c 100644 --- a/ray-tracing-pbrt-scene/Cargo.toml +++ b/ray-tracing-pbrt-scene/Cargo.toml @@ -8,3 +8,4 @@ ray-tracing-core = { path = "../ray-tracing-core" } clap = { version = "4.5.41", features = ["derive"] } miette = { version = "7.6.0", features = ["fancy"] } nom = "8.0.0" +thiserror = "2.0.12" diff --git a/ray-tracing-pbrt-scene/example.pbrt b/ray-tracing-pbrt-scene/example.pbrt index 2b5ca95..d47557a 100644 --- a/ray-tracing-pbrt-scene/example.pbrt +++ b/ray-tracing-pbrt-scene/example.pbrt @@ -33,3 +33,4 @@ AttributeBegin "point2 uv" [ 0 0 1 0 1 1 0 1 ] AttributeEnd +" fd diff --git a/ray-tracing-pbrt-scene/src/lib.rs b/ray-tracing-pbrt-scene/src/lib.rs index 43482c1..e1c5846 100644 --- a/ray-tracing-pbrt-scene/src/lib.rs +++ b/ray-tracing-pbrt-scene/src/lib.rs @@ -1,23 +1,151 @@ use std::{ fs::File, - io::{BufRead, BufReader, Bytes, Read}, + io::{BufRead, BufReader, Bytes, Read, Seek, Write}, iter::Peekable, + os::unix::fs::FileExt, path::{Path, PathBuf}, }; -use miette::{Diagnostic, Error, IntoDiagnostic, Result, bail, miette}; +use miette::{ + Diagnostic, Error, IntoDiagnostic, Result, SourceCode, SourceSpan, SpanContents, bail, miette, +}; use nom::IResult; use ray_tracing_core::{ affine_transform::AffineTransform, math::{Dir3, Pos3}, prelude::Float, }; +use thiserror::Error; -struct Tokenizer>> { +#[derive(Debug)] +struct SourceFile { + path: PathBuf, +} + +impl SourceCode for SourceFile { + fn read_span<'a>( + &'a self, + span: &miette::SourceSpan, + context_lines_before: usize, + context_lines_after: usize, + ) -> std::result::Result + 'a>, miette::MietteError> { + let mut file = std::fs::File::open(&self.path)?; + + // read keeping the last + + let mut data = Vec::new(); + + file.read_to_end(&mut data)?; + + let data = data.leak(); + + let line = data.iter().filter(|&&x| x == b'\n').count(); + + let mut start_new_lines = 0; + + let start_pos = data[0..span.offset()] + .iter() + .rposition(|&x| { + if x == b'\n' { + if start_new_lines > context_lines_before { + true + } else { + start_new_lines += 1; + false + } + } else { + false + } + }) + .map(|x| x + 1) + .unwrap_or(0); + + let mut end_new_lines = 0; + + let end_pos = data[span.offset()..] + .iter() + .position(|&x| { + if x == b'\n' { + if end_new_lines >= context_lines_after { + true + } else { + end_new_lines += 1; + false + } + } else { + false + } + }) + .map(|x| x + span.offset()) + .unwrap_or(data[span.offset()..].len()); + + let compact_data = &data[start_pos..end_pos]; + + Ok(Box::new(SourceFileSpanContents { + span: SourceSpan::new(start_pos.into(), end_pos - start_pos), + start_line_number: line - start_new_lines, + line_count: start_new_lines + 1 + end_new_lines, + path: self.path.clone(), + data: compact_data, + })) + } +} + +#[derive(Debug)] +struct SourceFileSpanContents { + data: &'static [u8], + span: SourceSpan, + start_line_number: usize, + line_count: usize, + path: PathBuf, +} + +impl<'a> SpanContents<'a> for SourceFileSpanContents { + fn data(&'_ self) -> &'a [u8] { + self.data + } + + fn span(&self) -> &SourceSpan { + &self.span + } + + fn line(&self) -> usize { + self.start_line_number + } + + fn column(&self) -> usize { + 0 + } + + fn line_count(&self) -> usize { + self.line_count + } + + fn name(&self) -> Option<&str> { + self.path.to_str() + } + + fn language(&self) -> Option<&str> { + None + } +} + +#[derive(Error, Debug, Diagnostic)] +#[error("oops!")] +#[diagnostic(help("justus ist doof"))] +struct MyBad { + #[source_code] + src: SourceFile, + + #[label("Here")] + bad_bit: SourceSpan, +} + +struct Tokenizer>> { input_iterator: Peekable, } -impl>> Tokenizer { +impl>> Tokenizer { fn new(input_iterator: I) -> Self { Self { input_iterator: input_iterator.peekable(), @@ -27,25 +155,24 @@ impl>> Tokenizer { impl Iterator for Tokenizer where - I: Iterator>, + I: Iterator>, { type Item = Result; fn next(&mut self) -> Option { - while self - .input_iterator - .peek() - .is_some_and(|c| c.as_ref().is_ok_and(|&c| c.is_whitespace() || c == '#')) - { + while self.input_iterator.peek().is_some_and(|c| { + c.as_ref() + .is_ok_and(|&(_, c)| c.is_whitespace() || c == '#') + }) { if self .input_iterator .peek() - .is_some_and(|c| c.as_ref().is_ok_and(|&c| c == '#')) + .is_some_and(|c| c.as_ref().is_ok_and(|&(_, c)| c == '#')) { while self .input_iterator .next() - .is_some_and(|c| c.is_ok_and(|c| c != '\n')) + .is_some_and(|c| c.is_ok_and(|(_, c)| c != '\n')) {} } else { match self.input_iterator.next()? { @@ -56,38 +183,43 @@ where } match self.input_iterator.next() { - Some(Ok('[')) => Some(Ok(String::from('['))), - Some(Ok(']')) => Some(Ok(String::from(']'))), - Some(Ok('"')) => { + Some(Ok((_, '['))) => Some(Ok(String::from('['))), + Some(Ok((_, ']'))) => Some(Ok(String::from(']'))), + Some(Ok((_, '"'))) => { let mut r = String::from('"'); while let Some(p) = self .input_iterator - .next_if(|c| c.as_ref().is_ok_and(|&c| c != '"')) + .next_if(|c| c.as_ref().is_ok_and(|&(_, c)| c != '"')) { match p { - Ok(c) => r.push(c), + Ok((_, c)) => r.push(c), Err(e) => return Some(Err(e)), } } if self .input_iterator .next() - .is_none_or(|c| !c.is_ok_and(|c| c == '"')) + .is_none_or(|c| !c.is_ok_and(|(_, c)| c == '"')) { - return Some(Err(miette::miette!("unfinished string"))); + return Some(Err(From::from(MyBad { + src: SourceFile { + path: PathBuf::from("ray-tracing-pbrt-scene/example.pbrt"), + }, + bad_bit: SourceSpan::new(40.into(), 4), + }))); }; r.push('"'); Some(Ok(r)) } - Some(Ok(c)) => { + Some(Ok((_, c))) => { let mut r = String::new(); r.push(c); while let Some(p) = self.input_iterator.next_if(|c| { c.as_ref() - .is_ok_and(|&c| c != '#' && c != '[' && c != ']' && !c.is_whitespace()) + .is_ok_and(|&(_, c)| c != '#' && c != '[' && c != ']' && !c.is_whitespace()) }) { match p { - Ok(c) => r.push(c), + Ok((_, c)) => r.push(c), Err(e) => return Some(Err(e)), } } @@ -99,11 +231,11 @@ where } } -struct Lexer>> { +struct Lexer>> { input: Peekable>, } -impl>> Lexer { +impl>> Lexer { fn new(iter: I) -> Self { Self { input: Tokenizer::new(iter).peekable(), @@ -174,7 +306,7 @@ fn parse_look_at(iter: &mut impl Iterator>) -> Result(iter: &mut Peekable>) -> Result where - I: Iterator>, + I: Iterator>, T: std::str::FromStr, ::Err: std::marker::Send + std::marker::Sync + std::error::Error + 'static, @@ -202,7 +334,7 @@ where fn parse_list(iter: &mut Peekable>, data: &mut Vec) -> Result<()> where - I: Iterator>, + I: Iterator>, T: std::str::FromStr, ::Err: std::marker::Send + std::marker::Sync + std::error::Error + 'static, @@ -237,7 +369,7 @@ fn parse_list_2( f: F, ) -> Result<()> where - I: Iterator>, + I: Iterator>, T: std::str::FromStr, ::Err: std::marker::Send + std::marker::Sync + std::error::Error + 'static, @@ -283,7 +415,7 @@ fn parse_list_3( f: F, ) -> Result<()> where - I: Iterator>, + I: Iterator>, T: std::str::FromStr, ::Err: std::marker::Send + std::marker::Sync + std::error::Error + 'static, @@ -331,7 +463,7 @@ where Ok(()) } -fn parse_shape>>( +fn parse_shape>>( iter: &mut Peekable>, ) -> std::result::Result { let shape_type = iter.next().ok_or(miette!("unable to get shape type"))??; @@ -558,7 +690,7 @@ fn parse_shape>>( } } -impl>> Lexer { +impl>> Lexer { fn next(&mut self, ctm: AffineTransform) -> Option> { match self.input.next() { Some(Ok(s)) => match s.as_str() { @@ -613,7 +745,7 @@ impl>> Lexer { } } -fn parse_transform>>( +fn parse_transform>>( input: &mut Peekable>, ) -> Result { if !input @@ -652,7 +784,7 @@ fn parse_transform>>( .ok_or(miette!("Unable to invert transformation"))?) } -fn parse_translate>>( +fn parse_translate>>( iter: &mut Peekable>, ) -> Result { let pos = Pos3::new( @@ -675,7 +807,7 @@ fn parse_translate>>( ))) } -fn parse_scale>>( +fn parse_scale>>( iter: &mut Peekable>, ) -> Result { Ok(Statement::ConcatTransform(AffineTransform::scale( @@ -694,7 +826,7 @@ fn parse_scale>>( ))) } -fn parse_rotate>>( +fn parse_rotate>>( iter: &mut Peekable>, ) -> Result { let angle = iter @@ -722,17 +854,25 @@ fn parse_rotate>>( ))) } struct BytesToChar { + count: usize, iter: I, } +impl BytesToChar { + fn new(iter: I) -> Self { + Self { count: 0, iter } + } +} + impl>> Iterator for BytesToChar { - type Item = Result; + type Item = Result<(usize, char)>; fn next(&mut self) -> Option { match self.iter.next()? { Ok(a) => { + self.count += 1; if a & 0x80 == 0 { - Some(Ok(char::from(a))) + Some(Ok((self.count, char::from(a)))) } else { todo!() } @@ -755,9 +895,7 @@ impl + std::fmt::Debug> Parser

{ Ok(Self { path, inner: None, - iter: Lexer::new(BytesToChar { - iter: bufreader.bytes(), - }), + iter: Lexer::new(BytesToChar::new(bufreader.bytes())), }) } }