partial: prototyping proto -> wit

This commit is contained in:
Sandipsinh Rathod 2024-12-22 17:24:24 -05:00
parent c4ceb92e11
commit 1b1a70f5e1
10 changed files with 67 additions and 171 deletions

@ -1,145 +0,0 @@
use base64::Engine;
use tailcall_valid::{Valid, Validator};
use crate::config::config::{Config, Field, Interface, Record};
use crate::config::wit_types::WitType;
use crate::merge_right::MergeRight;
use crate::tryfold::TryFold;
pub fn fix_args(config: Config) -> Valid<Config, anyhow::Error, anyhow::Error> {
Valid::succeed(config)
.and_then(|mut config| {
Valid::from_iter(config.interfaces.iter().cloned().collect::<Vec<_>>(), |mut interface| {
Valid::from_iter(interface.records.iter().cloned(), |mut record| {
Valid::from_iter(record.fields.iter().cloned(), |field| {
if !field.field_type.is_kind_of_primitive() {
fix_field()
.try_fold(&(&config, &interface, &record, &field, &field.field_type), Field::default())
.and_then(|field| {
Valid::succeed(Some(field))
})
}else {
Valid::succeed(None)
}
}).and_then(|v| {
let fields = v.into_iter().filter_map(|x| x).collect();
record.added_fields = fields;
Valid::succeed(record)
})
}).and_then(|records| {
interface.records = records.into_iter().collect();
Valid::succeed(interface)
})
}).and_then(|interfaces| {
config.interfaces = interfaces.into_iter().collect();
/*for interface in interfaces {
if let Some(interface) = config.interfaces.iter().find(|i| i.name == interface.name) {
for record in interface.records {
if let Some(mut record) = interface.records.iter().find(|r| r.name == record.name).cloned() {
for field in record.fields {
if let Some(field) = record.fields.iter().find(|f| f.name == field.name) {
let mut new_field = field.clone();
new_field.field_type = field.field_type.clone().merge_right(new_field.field_type.clone());
record.fields.remove(&field);
record.fields.insert(new_field);
}
}
}
}
}else {
config.interfaces.insert(interface);
}
}*/
/* let mut new_interfaces = BTreeSet::new();
for mut interface in config.interfaces {
let mut new_records = BTreeSet::new();
for mut record in interface.records {
let mut new_fields = BTreeSet::new();
for mut field in record.fields {
let mut new_field = interfaces
.iter()
.find(|i| i.name == interface.name).and_then(|interface| interface.records.iter().find(|r| r.name == record.name).and_then(|record|record.fields.iter().find(|f| f.name == field.name)))
.unwrap_or(&field)
.clone();
new_field = new_field.merge_right(field);
new_fields.insert(new_field);
}
record.fields = new_fields;
new_records.insert(record);
}
interface.records = new_records;
new_interfaces.insert(interface);
}
config.interfaces = new_interfaces;*/
// config.interfaces = config.interfaces.merge_right(map);
Valid::succeed(config)
})
})
}
/*
interface types {
record error { error: { message: string, details: list<{ field: string, message: string }>, code: string } }
record todo { completed: bool, created-at: string, description: string, due-date: string, id: string, title: string, updated-at: string, user-id: string }
record todo-create { description: string, due-date: string, title: string, user-id: string }
record todo-list { data: list<{ id: string, user-id: string, title: string, due-date: string, created-at: string, updated-at: string, completed: bool, description: string }>, metadata: { total: s32, offset: s32, limit: s32 } }
record todo-response { data: { id: string, user-id: string, title: string, due-date: string, created-at: string, updated-at: string, completed: bool, description: string } }
record todo-update { completed: bool, description: string, due-date: string, title: string }
}
*/
fn fix_field<'a>() -> TryFold<'a, (&'a Config, &'a Interface, &'a Record, &'a Field, &'a WitType), Field, anyhow::Error> {
TryFold::<(&Config, &Interface, &Record, &Field, &WitType), Field, anyhow::Error>::new(move |(config, interface, rec, field, wit), o| {
match &wit {
WitType::Option(x) => {
return fix_field().try_fold(&(*config, *interface, *rec, *field, x), o);
}
WitType::Result(a, b) => {
// TODO: this impl needs check.
// eg: -> result<record A {}, record B {}>
// this does not make sense to resolve with rec.name-A/B
return if !a.is_primitive() {
fix_field().try_fold(&(*config, *interface, *rec, *field, a), o)
} else if !b.is_primitive() {
fix_field().try_fold(&(*config, *interface, *rec, *field, b), o)
} else {
// TODO: Fix the possible conflicts here
fix_field().try_fold(&(*config, *interface, *rec, *field, a), o)
.and_then(|new_interface| fix_field().try_fold(&(*config, *interface, *rec, *field, b), new_interface))
};
}
WitType::List(x) => fix_field().try_fold(&(*config, *interface, *rec, *field, x.as_ref()), o),
WitType::Tuple(x) => {
// TODO: Fix the possible conflicts here
return Valid::from_iter(x.iter(), |x| fix_field().try_fold(&(*config, *interface, *rec, *field, x), o.clone()))
.and_then(|v| Valid::succeed(v.into_iter().fold((*field).clone(), |a, b| {
a.merge_right(b)
})));
}
WitType::Record(records) => {
let field_name = if field.name.is_empty() {
base64::prelude::BASE64_STANDARD.encode(field.name.as_bytes())
} else {
field.name.clone()
};
let name = format!("{}-{}", rec.name, field_name);
let new_field = Field {
name,
field_type: WitType::Record(records.clone()),
};
Valid::succeed(new_field)
}
WitType::FieldTy(_) => Valid::succeed(o),
// Ideally this case should never happen,
// but we should always throw an error to avoid infinite recursion
_ => return Valid::fail(anyhow::anyhow!("Unknown type: {:?}", field.field_type)),
}
})
}

@ -1,5 +1,3 @@
pub mod config;
pub mod wit_types;
pub mod to_wit;
pub mod fixargs;
pub mod handle_files;

@ -40,26 +40,6 @@ pub enum WitType {
}
impl WitType {
pub fn is_primitive(&self) -> bool {
match self {
WitType::Bool | WitType::U8 | WitType::U16 | WitType::U32 | WitType::U64 | WitType::S8 | WitType::S16 | WitType::S32 | WitType::S64 | WitType::Float32 | WitType::Float64 | WitType::Char | WitType::String => true,
_ => false,
}
}
pub fn is_kind_of_primitive(&self) -> bool {
match self {
WitType::Option(x) => x.is_primitive(),
WitType::Result(a, b) => a.is_primitive() && b.is_primitive(),
WitType::List(x) => x.is_primitive(),
WitType::Tuple(x) => x.iter().all(|x| x.is_primitive()),
WitType::Variant(_) => true,
WitType::Enum(_) => true,
WitType::Flags(_) => true,
WitType::Handle(_) => true,
WitType::TypeAlias(_, _) => true,
v => v.is_primitive(),
}
}
pub fn from_schema(
schema: &Schema,
openapi: &OpenApiSpec<Resolved>,

@ -12,6 +12,7 @@ mod transform;
mod tryfold;
mod merge_right;
mod primitive;
mod proto;
#[derive(Debug, Clone)]
pub struct WIPValue(Value);

@ -1,2 +1,3 @@
pub mod openapi_spec;
pub mod openapi;
pub mod openapi;
pub(super) mod handle_files;

@ -4,9 +4,8 @@ use anyhow::Error;
use convert_case::{Case, Casing};
use schemars::JsonSchema;
use tailcall_valid::{Valid, Validator};
use crate::config::fixargs::fix_args;
use crate::config::handle_files::handle_types;
use crate::config::config::Config;
use crate::openapi::handle_files::handle_types;
#[derive(Default)]
pub struct Unresolved;
@ -250,7 +249,6 @@ impl OpenApiSpec<Resolved> {
pub fn to_config(&self) -> Valid<Config, Error, Error> {
Valid::succeed(Config::default())
.and_then(|config| handle_types(config, &self))
.and_then(|config| fix_args(config))
}
}

45
src/proto/handle_types.rs Normal file

@ -0,0 +1,45 @@
use std::collections::BTreeSet;
use oas3::spec::ParameterIn::Path;
use protox::prost_reflect::prost_types::{field_descriptor_proto, FileDescriptorProto, FileDescriptorSet};
use tailcall_valid::{Valid, Validator};
use crate::config::config::{Config, Field, Interface, Record};
use crate::config::wit_types::WitType;
fn append_enums(config: &Config, file: &FileDescriptorProto) -> Valid<Record, anyhow::Error, anyhow::Error> {
todo!()
}
fn append_message(config: &Config, file: &FileDescriptorProto) -> Valid<Record, anyhow::Error, anyhow::Error> {
todo!()
}
pub fn handle_types(config: Config, proto: &[FileDescriptorSet], package: String) -> Valid<Config, anyhow::Error, anyhow::Error> {
Valid::succeed(config)
.and_then(|config| {
Valid::from_iter(proto.iter(), |set| {
Valid::from_iter(set.file.iter(), |file| {
append_enums(&config, file).and_then(|rec| {
append_message(&config, file)
.and_then(|mut new_rec| {
new_rec.fields.extend(rec.fields);
Valid::succeed(new_rec)
})
})
})
.and_then(|v| {
Valid::succeed(Interface {
name: "type".to_string(),
records: v.into_iter().collect(),
uses: vec![],
functions: vec![],
})
})
})
}).and_then(|v| {
Valid::succeed(Config {
package,
interfaces: v.into_iter().collect(),
world: Default::default(),
})
})
}

2
src/proto/mod.rs Normal file

@ -0,0 +1,2 @@
mod proto;
mod handle_types;

16
src/proto/proto.rs Normal file

@ -0,0 +1,16 @@
use protox::prost_reflect::prost_types::FileDescriptorSet;
use tailcall_valid::{Valid, Validator};
use crate::config::config::Config;
use crate::proto::handle_types::handle_types;
pub struct Proto(Vec<FileDescriptorSet>);
impl Proto {
pub fn new<T: IntoIterator<Item=FileDescriptorSet>>(v: T) -> Self {
Self(v.into_iter().collect())
}
pub fn to_config(&self) -> Valid<Config, anyhow::Error, anyhow::Error> {
Valid::succeed(Config::default())
.and_then(|config| handle_types(config, &self.0))
}
}