From b86292fadba095ac08d0e0cf4fd7dfd13ffc5d43 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 15 Apr 2024 20:16:54 +0200 Subject: [PATCH] fix diagnostic --- terustform-macros/src/lib.rs | 22 +++++------ terustform/src/framework/mod.rs | 63 +++++++++++++++++++++----------- terustform/src/lib.rs | 2 +- terustform/src/server/convert.rs | 32 ++++++++++++++-- terustform/src/values.rs | 14 ++++--- 5 files changed, 90 insertions(+), 43 deletions(-) diff --git a/terustform-macros/src/lib.rs b/terustform-macros/src/lib.rs index 7aec14c..5c86317 100644 --- a/terustform-macros/src/lib.rs +++ b/terustform-macros/src/lib.rs @@ -49,9 +49,9 @@ fn data_source_model_inner( quote! { let #tf::Some(#name) = obj.remove(#name_str) else { return #tf::Err( - #tf::Diagnostics::error_string( + #tf::Diagnostics::from(#tf::Diagnostic::error_string( format!("Expected property '{}', which was not present", #name_str), - ).with_path(path.clone()) + ).with_path(path.clone())) ); }; let #name = <#ty as #tf::ValueModel>::from_value( @@ -78,16 +78,16 @@ fn data_source_model_inner( fn from_value(v: #tf::Value, path: &#tf::AttrPath) -> #tf::DResult { match v { #tf::BaseValue::Unknown => { - return #tf::Err(#tf::Diagnostics::with_path( - #tf::Diagnostics::error_string(#tf::ToOwned::to_owned("Expected object, found unknown value")), + return #tf::Err(#tf::Diagnostics::from(#tf::Diagnostic::with_path( + #tf::Diagnostic::error_string(#tf::ToOwned::to_owned("Expected object, found unknown value")), #tf::Clone::clone(&path), - )); + ))); }, #tf::BaseValue::Null => { - return #tf::Err(#tf::Diagnostics::with_path( - #tf::Diagnostics::error_string(#tf::ToOwned::to_owned("Expected object, found null value")), + return #tf::Err(#tf::Diagnostics::from(#tf::Diagnostic::with_path( + #tf::Diagnostic::error_string(#tf::ToOwned::to_owned("Expected object, found null value")), #tf::Clone::clone(&path), - )); + ))); }, #tf::BaseValue::Known(#tf::ValueKind::Object(mut obj)) => { #(#field_extractions)* @@ -97,10 +97,10 @@ fn data_source_model_inner( }) }, #tf::BaseValue::Known(v) => { - return #tf::Err(#tf::Diagnostics::with_path( - #tf::Diagnostics::error_string(format!("Expected object, found {} value", v.diagnostic_type_str())), + return #tf::Err(#tf::Diagnostics::from(#tf::Diagnostic::with_path( + #tf::Diagnostic::error_string(format!("Expected object, found {} value", v.diagnostic_type_str())), #tf::Clone::clone(&path), - )); + ))); }, } } diff --git a/terustform/src/framework/mod.rs b/terustform/src/framework/mod.rs index cc60292..4a32aa4 100644 --- a/terustform/src/framework/mod.rs +++ b/terustform/src/framework/mod.rs @@ -9,41 +9,58 @@ use self::datasource::DataSource; #[derive(Debug, Default)] pub struct Diagnostics { - pub(crate) errors: Vec, - pub(crate) attr: Option, + pub(crate) diags: Vec, // note: lol this cannot contain warnings that would be fucked oops } +#[derive(Debug)] +pub struct Diagnostic { + pub(crate) msg: String, + pub(crate) attr: Option, +} + pub type DResult = Result; -impl Diagnostics { +impl Diagnostic { pub fn error_string(msg: impl Into) -> Self { - Self { - errors: vec![msg.into()], + Diagnostic { + msg: msg.into(), attr: None, } } - pub fn with_path(mut self, path: AttrPath) -> Self { self.attr = Some(path); self } +} +impl Diagnostics { pub fn has_errors(&self) -> bool { - !self.errors.is_empty() + !self.diags.is_empty() } } -impl From for Diagnostics { +impl From for Diagnostic { fn from(value: E) -> Self { Self::error_string(format!("{:?}", value)) } } +impl From for Diagnostics { + fn from(value: E) -> Self { + Diagnostic::from(value).into() + } +} + +impl From for Diagnostics { + fn from(value: Diagnostic) -> Self { + Self { diags: vec![value] } + } +} // TODO: this could probably be a clever 0-alloc &-based linked list! #[derive(Debug, Clone, Default)] -pub struct AttrPath(Vec); +pub struct AttrPath(pub(crate) Vec); #[derive(Debug, Clone)] pub enum AttrPathSegment { @@ -91,13 +108,14 @@ impl BaseValue { pub fn expect_known(&self, path: AttrPath) -> DResult<&T> { match self { - BaseValue::Null => { - Err(Diagnostics::error_string("expected value, found null value").with_path(path)) - } - BaseValue::Unknown => Err(Diagnostics::error_string( + BaseValue::Null => Err(Diagnostic::error_string("expected value, found null value") + .with_path(path) + .into()), + BaseValue::Unknown => Err(Diagnostic::error_string( "expected known value, found unknown value", ) - .with_path(path)), + .with_path(path) + .into()), BaseValue::Known(v) => Ok(v), } } @@ -111,13 +129,16 @@ pub trait ValueModel: Sized { impl ValueModel for StringValue { fn from_value(v: Value, path: &AttrPath) -> DResult { - v.try_map(|v| match v { - ValueKind::String(s) => Ok(s), - _ => Err(Diagnostics::error_string(format!( - "expected string, found {}", - v.diagnostic_type_str() - )) - .with_path(path.clone())), + v.try_map(|v| -> DResult { + match v { + ValueKind::String(s) => Ok(s), + _ => Err(Diagnostic::error_string(format!( + "expected string, found {}", + v.diagnostic_type_str() + )) + .with_path(path.clone()) + .into()), + } }) } diff --git a/terustform/src/lib.rs b/terustform/src/lib.rs index 877cc62..2667d20 100644 --- a/terustform/src/lib.rs +++ b/terustform/src/lib.rs @@ -105,7 +105,7 @@ async fn init_handshake(server_cert: &rcgen::Certificate) -> Result<(tempfile::T #[doc(hidden)] pub mod __derive_private { pub use crate::framework::{ - AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostics, ValueModel, + AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostic, Diagnostics, ValueModel, }; pub use crate::values::{Value, ValueKind}; pub use {Clone, Option::Some, Result::Err, ToOwned}; diff --git a/terustform/src/server/convert.rs b/terustform/src/server/convert.rs index 1ee4e8f..751e6b7 100644 --- a/terustform/src/server/convert.rs +++ b/terustform/src/server/convert.rs @@ -1,7 +1,7 @@ use crate::{ framework::{ datasource::{self, Mode}, - Diagnostics, + AttrPathSegment, Diagnostics, }, values::Type, }; @@ -78,13 +78,37 @@ impl datasource::Attribute { impl Diagnostics { pub(crate) fn to_tfplugin_diags(self) -> Vec { - self.errors + self.diags .into_iter() .map(|err| tfplugin6::Diagnostic { severity: tfplugin6::diagnostic::Severity::Error as _, - summary: err, + summary: err.msg, detail: "".to_owned(), - attribute: None, + attribute: err.attr.map(|attr| -> tfplugin6::AttributePath { + tfplugin6::AttributePath { + steps: attr + .0 + .into_iter() + .map(|segment| { + use tfplugin6::attribute_path::step::Selector; + + tfplugin6::attribute_path::Step { + selector: Some(match segment { + AttrPathSegment::AttributeName(name) => { + Selector::AttributeName(name) + } + AttrPathSegment::ElementKeyString(key) => { + Selector::ElementKeyString(key) + } + AttrPathSegment::ElementKeyInt(key) => { + Selector::ElementKeyInt(key) + } + }), + } + }) + .collect(), + } + }), }) .collect() } diff --git a/terustform/src/values.rs b/terustform/src/values.rs index 69735cd..ec0abd4 100644 --- a/terustform/src/values.rs +++ b/terustform/src/values.rs @@ -6,7 +6,7 @@ use std::{ io::{self, Read}, }; -use crate::framework::{BaseValue, DResult, Diagnostics}; +use crate::framework::{BaseValue, DResult, Diagnostic}; #[derive(Debug)] pub enum Type { @@ -250,16 +250,17 @@ impl Value { let len = mp::read_map_len(rd)?; if attrs.len() != (len as usize) { - return Err(Diagnostics::error_string(format!( + return Err(Diagnostic::error_string(format!( "expected {} attrs, found {len} attrs in object", attrs.len() - ))); + )) + .into()); } let elems = (0..len) .map(|_| -> DResult<_> { let key = read_string(rd)?; let typ = attrs.get(&key).ok_or_else(|| { - Diagnostics::error_string(format!("unexpected attribute: '{key}'")) + Diagnostic::error_string(format!("unexpected attribute: '{key}'")) })?; let value = Value::msg_unpack_inner(rd, &typ)?; Ok((key, value)) @@ -270,10 +271,11 @@ impl Value { Type::Tuple { elems } => { let len = mp::read_array_len(rd)?; if elems.len() != (len as usize) { - return Err(Diagnostics::error_string(format!( + return Err(Diagnostic::error_string(format!( "expected {} elems, found {len} elems in tuple", elems.len() - ))); + )) + .into()); } let elems = elems