more movement

This commit is contained in:
nora 2024-04-15 20:26:55 +02:00
parent 7e479e7a28
commit 991642b90d
4 changed files with 100 additions and 101 deletions

View file

@ -3,8 +3,7 @@ use std::collections::HashMap;
use terustform::{ use terustform::{
datasource::{self, DataSource}, datasource::{self, DataSource},
provider::Provider, provider::Provider,
values::Value, AttrPath, DResult, StringValue, Value, ValueModel,
AttrPath, DResult, StringValue, ValueModel,
}; };
#[tokio::main] #[tokio::main]

View file

@ -1,5 +1,3 @@
use crate::values::{Value, ValueKind};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Diagnostics { pub struct Diagnostics {
pub(crate) diags: Vec<Diagnostic>, pub(crate) diags: Vec<Diagnostic>,
@ -14,6 +12,18 @@ pub struct Diagnostic {
pub type DResult<T> = Result<T, Diagnostics>; pub type DResult<T> = Result<T, Diagnostics>;
// TODO: this could probably be a clever 0-alloc &-based linked list!
#[derive(Debug, Clone, Default)]
pub struct AttrPath(pub(crate) Vec<AttrPathSegment>);
#[derive(Debug, Clone)]
pub enum AttrPathSegment {
AttributeName(String),
ElementKeyString(String),
ElementKeyInt(i64),
}
impl Diagnostic { impl Diagnostic {
pub fn error_string(msg: impl Into<String>) -> Self { pub fn error_string(msg: impl Into<String>) -> Self {
Diagnostic { Diagnostic {
@ -33,6 +43,20 @@ impl Diagnostics {
} }
} }
impl AttrPath {
pub fn root() -> Self {
Self::default()
}
pub fn attr(name: impl Into<String>) -> Self {
Self(vec![AttrPathSegment::AttributeName(name.into())])
}
pub fn append_attribute_name(&self, name: String) -> Self {
let mut p = self.clone();
p.0.push(AttrPathSegment::AttributeName(name));
p
}
}
impl<E: std::error::Error + std::fmt::Debug> From<E> for Diagnostic { impl<E: std::error::Error + std::fmt::Debug> From<E> for Diagnostic {
fn from(value: E) -> Self { fn from(value: E) -> Self {
Self::error_string(format!("{:?}", value)) Self::error_string(format!("{:?}", value))
@ -49,93 +73,3 @@ impl From<Diagnostic> for Diagnostics {
Self { diags: vec![value] } Self { diags: vec![value] }
} }
} }
// TODO: this could probably be a clever 0-alloc &-based linked list!
#[derive(Debug, Clone, Default)]
pub struct AttrPath(pub(crate) Vec<AttrPathSegment>);
#[derive(Debug, Clone)]
pub enum AttrPathSegment {
AttributeName(String),
ElementKeyString(String),
ElementKeyInt(i64),
}
impl AttrPath {
pub fn root() -> Self {
Self::default()
}
pub fn attr(name: impl Into<String>) -> Self {
Self(vec![AttrPathSegment::AttributeName(name.into())])
}
pub fn append_attribute_name(&self, name: String) -> Self {
let mut p = self.clone();
p.0.push(AttrPathSegment::AttributeName(name));
p
}
}
pub type StringValue = BaseValue<String>;
pub type I64Value = BaseValue<i64>;
#[derive(Debug)]
pub enum BaseValue<T> {
Unknown,
Null,
Known(T),
}
impl<T> BaseValue<T> {
fn map<U>(self, f: impl FnOnce(T) -> U) -> BaseValue<U> {
self.try_map(|v| Ok(f(v))).unwrap()
}
fn try_map<U>(self, f: impl FnOnce(T) -> DResult<U>) -> DResult<BaseValue<U>> {
Ok(match self {
Self::Unknown => BaseValue::Unknown,
Self::Null => BaseValue::Null,
Self::Known(v) => BaseValue::Known(f(v)?),
})
}
pub fn expect_known(&self, path: AttrPath) -> DResult<&T> {
match self {
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)
.into()),
BaseValue::Known(v) => Ok(v),
}
}
}
pub trait ValueModel: Sized {
fn from_value(v: Value, path: &AttrPath) -> DResult<Self>;
fn to_value(self) -> Value;
}
impl ValueModel for StringValue {
fn from_value(v: Value, path: &AttrPath) -> DResult<Self> {
v.try_map(|v| -> DResult<String> {
match v {
ValueKind::String(s) => Ok(s),
_ => Err(Diagnostic::error_string(format!(
"expected string, found {}",
v.diagnostic_type_str()
))
.with_path(path.clone())
.into()),
}
})
}
fn to_value(self) -> Value {
self.map(ValueKind::String)
}
}

View file

@ -1,11 +1,13 @@
mod base; mod diag;
mod server;
mod values;
pub mod datasource; pub mod datasource;
pub mod provider; pub mod provider;
mod server;
pub mod values;
pub use base::*; pub use diag::*;
pub use terustform_macros::Model; pub use terustform_macros::Model;
pub use values::*;
use provider::Provider; use provider::Provider;
@ -24,9 +26,9 @@ pub async fn start(provider: &dyn Provider) -> eyre::Result<()> {
/// Private, only for use for with the derive macro. /// Private, only for use for with the derive macro.
#[doc(hidden)] #[doc(hidden)]
pub mod __derive_private { pub mod __derive_private {
pub use crate::values::{Value, ValueKind};
pub use crate::{ pub use crate::{
AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostic, Diagnostics, ValueModel, AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostic, Diagnostics, Value, ValueKind,
ValueModel,
}; };
pub use {Clone, Option::Some, Result::Err, ToOwned}; pub use {Clone, Option::Some, Result::Err, ToOwned};

View file

@ -6,7 +6,7 @@ use std::{
io::{self, Read}, io::{self, Read},
}; };
use crate::{BaseValue, DResult, Diagnostic}; use crate::{AttrPath, DResult, Diagnostic};
#[derive(Debug)] #[derive(Debug)]
pub enum Type { pub enum Type {
@ -108,6 +108,70 @@ impl ValueKind {
} }
} }
pub type StringValue = BaseValue<String>;
pub type I64Value = BaseValue<i64>;
#[derive(Debug)]
pub enum BaseValue<T> {
Unknown,
Null,
Known(T),
}
impl<T> BaseValue<T> {
fn map<U>(self, f: impl FnOnce(T) -> U) -> BaseValue<U> {
self.try_map(|v| Ok(f(v))).unwrap()
}
fn try_map<U>(self, f: impl FnOnce(T) -> DResult<U>) -> DResult<BaseValue<U>> {
Ok(match self {
Self::Unknown => BaseValue::Unknown,
Self::Null => BaseValue::Null,
Self::Known(v) => BaseValue::Known(f(v)?),
})
}
pub fn expect_known(&self, path: AttrPath) -> DResult<&T> {
match self {
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)
.into()),
BaseValue::Known(v) => Ok(v),
}
}
}
pub trait ValueModel: Sized {
fn from_value(v: Value, path: &AttrPath) -> DResult<Self>;
fn to_value(self) -> Value;
}
impl ValueModel for StringValue {
fn from_value(v: Value, path: &AttrPath) -> DResult<Self> {
v.try_map(|v| -> DResult<String> {
match v {
ValueKind::String(s) => Ok(s),
_ => Err(Diagnostic::error_string(format!(
"expected string, found {}",
v.diagnostic_type_str()
))
.with_path(path.clone())
.into()),
}
})
}
fn to_value(self) -> Value {
self.map(ValueKind::String)
}
}
// marshal msg pack // marshal msg pack
// tftypes/value.go:MarshalMsgPack // tftypes/value.go:MarshalMsgPack