diff --git a/agdb/src/lib.rs b/agdb/src/lib.rs index 0ac4556e..d57eb726 100644 --- a/agdb/src/lib.rs +++ b/agdb/src/lib.rs @@ -44,9 +44,70 @@ pub use agdb_derive::{DbElement, DbSerialize, DbType, DbTypeMarker, DbValue}; #[cfg(feature = "api")] pub mod type_def; + #[cfg(feature = "api")] pub use agdb_derive::{TypeDef, TypeDefImpl, fn_def, impl_def, test_def, trait_def}; +#[cfg(feature = "api")] +#[rustfmt::skip] +pub use { + db::db_value::DbValues, + query::query_aliases::QueryAliases, + query::query_values::MultiValues, + query::query_values::SingleValues, + query_builder::insert::Insert, + query_builder::insert_aliases::InsertAliases, + query_builder::insert_aliases::InsertAliasesIds, + query_builder::insert_edge::InsertEdges, + query_builder::insert_edge::InsertEdgesEach, + query_builder::insert_edge::InsertEdgesFrom, + query_builder::insert_edge::InsertEdgesFromTo, + query_builder::insert_edge::InsertEdgesIds, + query_builder::insert_edge::InsertEdgesValues, + query_builder::insert_index::InsertIndex, + query_builder::insert_nodes::InsertNodes, + query_builder::insert_nodes::InsertNodesAliases, + query_builder::insert_nodes::InsertNodesCount, + query_builder::insert_nodes::InsertNodesIds, + query_builder::insert_nodes::InsertNodesValues, + query_builder::insert_values::InsertValues, + query_builder::insert_values::InsertValuesIds, + query_builder::remove::Remove, + query_builder::remove_aliases::RemoveAliases, + query_builder::remove_ids::RemoveIds, + query_builder::remove_index::RemoveIndex, + query_builder::remove_values::RemoveValues, + query_builder::remove_values::RemoveValuesIds, + query_builder::search::Search, + query_builder::search::SearchAlgorithm, + query_builder::search::SearchFrom, + query_builder::search::SearchIndex as SearchIndexBuilder, + query_builder::search::SearchIndexValue, + query_builder::search::SearchOrderBy, + query_builder::search::SearchQueryBuilder, + query_builder::search::SearchQueryBuilderDef, + query_builder::search::SearchTo, + query_builder::search::SelectLimit, + query_builder::search::SelectOffset, + query_builder::select::Select, + query_builder::select_aliases::SelectAliases, + query_builder::select_aliases::SelectAliasesIds, + query_builder::select_edge_count::SelectEdgeCount, + query_builder::select_edge_count::SelectEdgeCountIds, + query_builder::select_ids::SelectIds, + query_builder::select_indexes::SelectIndexes, + query_builder::select_key_count::SelectKeyCount, + query_builder::select_key_count::SelectKeyCountIds, + query_builder::select_keys::SelectKeys, + query_builder::select_keys::SelectKeysIds, + query_builder::select_node_count::SelectNodeCount, + query_builder::select_values::SelectValues, + query_builder::select_values::SelectValuesIds, + query_builder::where_::Where, + query_builder::where_::WhereKey, + query_builder::where_::WhereLogicOperator, +}; + pub use db::Db; pub use db::DbAny; pub use db::DbAnyTransaction; diff --git a/agdb/src/type_def/trait_def.rs b/agdb/src/type_def/trait_def.rs index 96d3679a..8bee1d57 100644 --- a/agdb/src/type_def/trait_def.rs +++ b/agdb/src/type_def/trait_def.rs @@ -15,6 +15,7 @@ mod tests { use crate::type_def::GenericKind; use crate::type_def::Literal; use crate::type_def::Type; + use crate::type_def::TypeDefinition; #[test] fn empty_trait() { @@ -22,7 +23,7 @@ mod tests { #[allow(dead_code)] trait MyTrait {} - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -35,7 +36,7 @@ mod tests { #[allow(dead_code)] trait MyTrait {} - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -59,7 +60,7 @@ mod tests { { } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -79,7 +80,7 @@ mod tests { #[allow(dead_code)] trait MyTrait: agdb::type_def::TypeDefinition {} - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -99,7 +100,7 @@ mod tests { async fn b(v: i32) -> String; } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -143,7 +144,7 @@ mod tests { fn id(v: T) -> T; } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -178,7 +179,7 @@ mod tests { fn get(&'a self) -> &'a str; } - let Type::Trait(def) = __MyLifetimeTrait_type_def() else { + let Type::Trait(def) = MyLifetimeTraitDef::type_def() else { panic!("Expected trait type definition"); }; @@ -210,7 +211,7 @@ mod tests { #[allow(dead_code)] trait MyConstTrait {} - let Type::Trait(def) = __MyConstTrait_type_def() else { + let Type::Trait(def) = MyConstTraitDef::type_def() else { panic!("Expected trait type definition"); }; @@ -235,7 +236,7 @@ mod tests { } } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -259,7 +260,7 @@ mod tests { fn without_default(); } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -287,7 +288,7 @@ mod tests { } } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -324,7 +325,7 @@ mod tests { } } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -351,7 +352,7 @@ mod tests { } } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -373,7 +374,7 @@ mod tests { ) -> Result<(u16, T), Option>>; } - let Type::Trait(def) = __HttpLike_type_def() else { + let Type::Trait(def) = HttpLikeDef::type_def() else { panic!("Expected a trait type definition"); }; diff --git a/agdb/tests/api_def_reflection_test.rs b/agdb/tests/api_def_reflection_test.rs index 396fff7b..d803be86 100644 --- a/agdb/tests/api_def_reflection_test.rs +++ b/agdb/tests/api_def_reflection_test.rs @@ -873,7 +873,7 @@ fn empty_trait() { #[expect(dead_code)] trait MyTrait {} - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -886,7 +886,7 @@ fn trait_with_generics() { #[expect(dead_code)] trait MyTrait {} - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -905,7 +905,7 @@ fn trait_with_where_clause() { { } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -919,7 +919,7 @@ fn trait_with_supertrait() { #[expect(dead_code)] trait MyTrait: agdb::type_def::TypeDefinition {} - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -935,7 +935,7 @@ fn trait_with_functions() { async fn b(v: i32) -> String; } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -958,7 +958,7 @@ fn trait_function_with_generics() { fn id(v: T) -> T; } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -979,7 +979,7 @@ fn trait_with_lifetime() { fn get(&'a self) -> &'a str; } - let Type::Trait(def) = __MyLifetimeTrait_type_def() else { + let Type::Trait(def) = MyLifetimeTraitDef::type_def() else { panic!("Expected trait type definition"); }; @@ -996,7 +996,7 @@ fn trait_with_const_generic() { #[expect(dead_code)] trait MyConstTrait {} - let Type::Trait(def) = __MyConstTrait_type_def() else { + let Type::Trait(def) = MyConstTraitDef::type_def() else { panic!("Expected trait type definition"); }; @@ -1014,7 +1014,7 @@ fn trait_function_with_default_implementation() { } } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -1031,7 +1031,7 @@ fn trait_function_without_default_implementation() { fn without_default(); } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -1053,7 +1053,7 @@ fn trait_mixed_default_and_non_default_functions() { } } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -1074,7 +1074,7 @@ fn trait_default_function_with_generics() { } } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; @@ -1092,7 +1092,7 @@ fn trait_default_async_function() { } } - let Type::Trait(def) = __MyTrait_type_def() else { + let Type::Trait(def) = MyTraitDef::type_def() else { panic!("Expected a trait type definition"); }; diff --git a/agdb_api/rust/src/api.rs b/agdb_api/rust/src/api.rs new file mode 100644 index 00000000..8d2735eb --- /dev/null +++ b/agdb_api/rust/src/api.rs @@ -0,0 +1,448 @@ +use agdb::Comparison; +use agdb::CountComparison; +use agdb::DbElement; +use agdb::DbF64; +use agdb::DbId; +use agdb::DbKeyOrder; +use agdb::DbKeyOrders; +use agdb::DbKeyValue; +use agdb::DbValue; +use agdb::DbValues; +use agdb::Insert; +use agdb::InsertAliases; +use agdb::InsertAliasesIds; +use agdb::InsertAliasesQuery; +use agdb::InsertEdges; +use agdb::InsertEdgesEach; +use agdb::InsertEdgesFrom; +use agdb::InsertEdgesFromTo; +use agdb::InsertEdgesIds; +use agdb::InsertEdgesQuery; +use agdb::InsertEdgesValues; +use agdb::InsertIndex; +use agdb::InsertIndexQuery; +use agdb::InsertNodes; +use agdb::InsertNodesAliases; +use agdb::InsertNodesCount; +use agdb::InsertNodesIds; +use agdb::InsertNodesQuery; +use agdb::InsertNodesValues; +use agdb::InsertValues; +use agdb::InsertValuesIds; +use agdb::InsertValuesQuery; +use agdb::KeyValueComparison; +use agdb::MultiValues; +use agdb::QueryAliases; +use agdb::QueryBuilder; +use agdb::QueryCondition; +use agdb::QueryConditionData; +use agdb::QueryConditionLogic; +use agdb::QueryConditionModifier; +use agdb::QueryId; +use agdb::QueryIds; +use agdb::QueryResult; +use agdb::QueryType; +use agdb::QueryValues; +use agdb::Remove; +use agdb::RemoveAliases; +use agdb::RemoveAliasesQuery; +use agdb::RemoveIds; +use agdb::RemoveIndex; +use agdb::RemoveIndexQuery; +use agdb::RemoveQuery; +use agdb::RemoveValues; +use agdb::RemoveValuesIds; +use agdb::RemoveValuesQuery; +use agdb::Search; +use agdb::SearchAlgorithm; +use agdb::SearchFrom; +use agdb::SearchIndexBuilder; +use agdb::SearchIndexValue; +use agdb::SearchOrderBy; +use agdb::SearchQuery; +use agdb::SearchQueryAlgorithm; +use agdb::SearchQueryBuilderDef; +use agdb::SearchTo; +use agdb::Select; +use agdb::SelectAliases; +use agdb::SelectAliasesIds; +use agdb::SelectAliasesQuery; +use agdb::SelectAllAliasesQuery; +use agdb::SelectEdgeCount; +use agdb::SelectEdgeCountIds; +use agdb::SelectEdgeCountQuery; +use agdb::SelectIds; +use agdb::SelectIndexes; +use agdb::SelectIndexesQuery; +use agdb::SelectKeyCount; +use agdb::SelectKeyCountIds; +use agdb::SelectKeyCountQuery; +use agdb::SelectKeys; +use agdb::SelectKeysIds; +use agdb::SelectKeysQuery; +use agdb::SelectLimit; +use agdb::SelectNodeCount; +use agdb::SelectNodeCountQuery; +use agdb::SelectOffset; +use agdb::SelectValues; +use agdb::SelectValuesIds; +use agdb::SelectValuesQuery; +use agdb::SingleValues; +use agdb::Where; +use agdb::WhereKey; +use agdb::WhereLogicOperator; +use agdb::type_def::Impl; +use agdb::type_def::ImplDefinition; +use agdb::type_def::Type; +use agdb::type_def::TypeDefinition; + +use crate::AdminStatus; +use crate::AgdbApiClientDef; +use crate::AgdbApiError; +use crate::ChangePassword; +use crate::ClusterStatus; +use crate::DbAudit; +use crate::DbKind; +use crate::DbResource; +use crate::DbUser; +use crate::DbUserRole; +use crate::HttpClientDef; +use crate::LogLevelFilter; +use crate::QueryAudit; +use crate::ServerDatabase; +use crate::UserCredentials; +use crate::UserLogin; +use crate::UserStatus; + +macro_rules! type_entry { + ($ty:ty) => { + (<$ty>::type_def(), vec![]) + }; + ($ty:ty, impl) => { + (<$ty>::type_def(), vec![<$ty>::impl_def()]) + }; +} + +pub struct Api; + +impl Api { + pub fn type_defs() -> Vec<(Type, Vec)> { + vec![ + // agdb DB types + type_entry!(DbElement), + type_entry!(DbF64), + type_entry!(DbId), + type_entry!(DbKeyOrder), + type_entry!(DbKeyOrders), + type_entry!(DbKeyValue), + type_entry!(DbValue), + type_entry!(DbValues), + // agdb query types + type_entry!(QueryType), + type_entry!(QueryAliases), + type_entry!(InsertAliasesQuery), + type_entry!(InsertEdgesQuery), + type_entry!(InsertIndexQuery), + type_entry!(InsertNodesQuery), + type_entry!(InsertValuesQuery), + type_entry!(Comparison), + type_entry!(CountComparison), + type_entry!(KeyValueComparison), + type_entry!(QueryCondition), + type_entry!(QueryConditionData), + type_entry!(QueryConditionLogic), + type_entry!(QueryConditionModifier), + type_entry!(QueryId), + type_entry!(QueryIds), + type_entry!(QueryResult), + type_entry!(QueryValues), + type_entry!(SingleValues), + type_entry!(MultiValues), + type_entry!(RemoveAliasesQuery), + type_entry!(RemoveIndexQuery), + type_entry!(RemoveQuery), + type_entry!(RemoveValuesQuery), + type_entry!(SearchQuery), + type_entry!(SearchQueryAlgorithm), + type_entry!(SelectAliasesQuery), + type_entry!(SelectAllAliasesQuery), + type_entry!(SelectEdgeCountQuery), + type_entry!(SelectIndexesQuery), + type_entry!(SelectKeyCountQuery), + type_entry!(SelectKeysQuery), + type_entry!(SelectNodeCountQuery), + type_entry!(SelectValuesQuery), + // agdb QueryBuilder types (with impl blocks) + type_entry!(QueryBuilder, impl), + type_entry!(Insert, impl), + type_entry!(InsertAliases, impl), + type_entry!(InsertAliasesIds, impl), + type_entry!(InsertEdges, impl), + type_entry!(InsertEdgesEach, impl), + type_entry!(InsertEdgesFrom, impl), + type_entry!(InsertEdgesFromTo, impl), + type_entry!(InsertEdgesIds, impl), + type_entry!(InsertEdgesValues, impl), + type_entry!(InsertIndex, impl), + type_entry!(InsertNodes, impl), + type_entry!(InsertNodesAliases, impl), + type_entry!(InsertNodesCount, impl), + type_entry!(InsertNodesIds, impl), + type_entry!(InsertNodesValues, impl), + type_entry!(InsertValues, impl), + type_entry!(InsertValuesIds, impl), + type_entry!(Remove, impl), + type_entry!(RemoveAliases, impl), + type_entry!(RemoveIds, impl), + type_entry!(RemoveIndex, impl), + type_entry!(RemoveValues, impl), + type_entry!(RemoveValuesIds, impl), + // Generic search/where builder types (monomorphised with SearchQuery) + type_entry!(Search, impl), + type_entry!(SearchAlgorithm, impl), + type_entry!(SearchFrom, impl), + type_entry!(SearchTo, impl), + type_entry!(SearchIndexBuilder, impl), + type_entry!(SearchIndexValue, impl), + type_entry!(SearchOrderBy, impl), + type_entry!(SelectLimit, impl), + type_entry!(SelectOffset, impl), + type_entry!(Select, impl), + type_entry!(SelectAliases, impl), + type_entry!(SelectAliasesIds, impl), + type_entry!(SelectEdgeCount, impl), + type_entry!(SelectEdgeCountIds, impl), + type_entry!(SelectIds, impl), + type_entry!(SelectIndexes, impl), + type_entry!(SelectKeyCount, impl), + type_entry!(SelectKeyCountIds, impl), + type_entry!(SelectKeys, impl), + type_entry!(SelectKeysIds, impl), + type_entry!(SelectNodeCount, impl), + type_entry!(SelectValues, impl), + type_entry!(SelectValuesIds, impl), + type_entry!(Where, impl), + type_entry!(WhereKey, impl), + type_entry!(WhereLogicOperator, impl), + // agdb_api traits + type_entry!(SearchQueryBuilderDef), + type_entry!(HttpClientDef), + type_entry!(AgdbApiClientDef), + // agdb_api types + type_entry!(AgdbApiError), + type_entry!(AdminStatus), + type_entry!(ChangePassword), + type_entry!(ClusterStatus), + type_entry!(DbAudit), + type_entry!(DbKind), + type_entry!(DbResource), + type_entry!(DbUser), + type_entry!(DbUserRole), + type_entry!(LogLevelFilter), + type_entry!(QueryAudit), + type_entry!(ServerDatabase), + type_entry!(UserCredentials), + type_entry!(UserLogin), + type_entry!(UserStatus), + ] + } +} + +#[cfg(test)] +mod tests { + use super::*; + use agdb::type_def::Function; + use agdb::type_def::Generic; + use std::collections::HashSet; + + fn collect_from_generic(g: &Generic, out: &mut Vec Type>) { + out.extend_from_slice(g.bounds); + } + + fn collect_from_function(f: &Function, out: &mut Vec Type>) { + out.push(f.ret); + for arg in f.args { + if let Some(ty) = arg.ty { + out.push(ty); + } + } + for g in f.generics { + collect_from_generic(g, out); + } + } + + fn collect_from_impl(i: &Impl, out: &mut Vec Type>) { + out.push(i.ty); + if let Some(t) = i.trait_ { + out.push(t); + } + for g in i.generics { + collect_from_generic(g, out); + } + for f in i.functions { + collect_from_function(f, out); + } + } + + fn collect_fn_ptrs(ty: &Type, out: &mut Vec Type>) { + match ty { + Type::Option(f) | Type::Slice(f) | Type::Vec(f) => out.push(*f), + Type::Result { ok, err } => { + out.push(*ok); + out.push(*err); + } + Type::Reference(r) => out.push(r.ty), + Type::Pointer(p) => out.push(p.ty), + Type::Tuple(fns) => out.extend_from_slice(fns), + Type::Enum(e) => { + for v in e.variants { + if let Some(f) = v.ty { + out.push(f); + } + } + for g in e.generics { + collect_from_generic(g, out); + } + for f in e.functions { + collect_from_function(f, out); + } + } + Type::Struct(s) => { + for v in s.fields { + if let Some(f) = v.ty { + out.push(f); + } + } + for g in s.generics { + collect_from_generic(g, out); + } + for f in s.functions { + collect_from_function(f, out); + } + } + Type::Function(f) | Type::Test(f) => collect_from_function(f, out), + Type::Impl(i) => collect_from_impl(i, out), + Type::Trait(t) => { + out.extend_from_slice(t.bounds); + for g in t.generics { + collect_from_generic(g, out); + } + for f in t.functions { + collect_from_function(f, out); + } + } + Type::Generic(g) => collect_from_generic(g, out), + Type::Literal(_) | Type::SelfType(_) => {} + } + } + + #[test] + fn all_fn_ptrs_resolvable() { + let roots = Api::type_defs(); + let mut visited: HashSet = HashSet::new(); + let mut queue: Vec Type> = Vec::new(); + + for (ty, impls) in &roots { + collect_fn_ptrs(ty, &mut queue); + for impl_ in impls { + collect_from_impl(impl_, &mut queue); + } + } + + while let Some(f) = queue.pop() { + let addr = f as usize; + if !visited.insert(addr) { + continue; + } + let ty = f(); + collect_fn_ptrs(&ty, &mut queue); + } + } + + // Traits from external crates or Rust std that appear as generic bounds + // but are not part of the agdb/agdb_api public API catalog. + const EXTERNAL_TRAIT_ALLOWLIST: &[&str] = &[ + // std / core + "Borrow", + "Clone", + "Copy", + "Debug", + "Default", + "Display", + "Eq", + "From", + "Hash", + "Into", + "Iterator", + "Ord", + "PartialEq", + "PartialOrd", + "Send", + "Sync", + // serde + "DeserializeOwned", + "Deserialize", + "Serialize", + // agdb database traits (Rust-specific, not cross-language API types) + "DbType", + "DbTypeMarker", + // agdb reflection meta-traits (infrastructure, not public API types) + "TypeDefinition", + "ImplDefinition", + ]; + + fn type_name(ty: &Type) -> Option<&'static str> { + match ty { + Type::Struct(s) => Some(s.name), + Type::Enum(e) => Some(e.name), + Type::Trait(t) => Some(t.name), + _ => None, + } + } + + #[test] + fn all_named_types_in_catalog() { + let roots = Api::type_defs(); + + // Build set of all root type names. + let root_names: HashSet<&'static str> = roots.iter().map(|(ty, _)| ty.name()).collect(); + + let mut visited: HashSet = HashSet::new(); + let mut queue: Vec Type> = Vec::new(); + + for (ty, impls) in &roots { + collect_fn_ptrs(ty, &mut queue); + for impl_ in impls { + collect_from_impl(impl_, &mut queue); + } + } + + let mut missing: Vec<&'static str> = Vec::new(); + + while let Some(f) = queue.pop() { + let addr = f as usize; + if !visited.insert(addr) { + continue; + } + let ty = f(); + + if let Some(name) = type_name(&ty) { + let in_catalog = root_names.contains(name); + let is_external = EXTERNAL_TRAIT_ALLOWLIST.contains(&name); + if !in_catalog && !is_external && !missing.contains(&name) { + missing.push(name); + } + } + + collect_fn_ptrs(&ty, &mut queue); + } + + assert!( + missing.is_empty(), + "The following types are referenced in the API type graph \ + but are not listed in Api::type_defs():\n {}\n\ + Add them to the catalog or to EXTERNAL_TRAIT_ALLOWLIST if they are external.", + missing.join(", ") + ); + } +} diff --git a/agdb_api/rust/src/lib.rs b/agdb_api/rust/src/lib.rs index 978a2644..1f0d7f82 100644 --- a/agdb_api/rust/src/lib.rs +++ b/agdb_api/rust/src/lib.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "api")] +pub mod api; mod api_error; mod api_result; mod api_types; @@ -25,3 +27,5 @@ pub use api_types::UserStatus; pub use client::AgdbApi; pub use http_client::HttpClient; pub use http_client::ReqwestClient; +#[cfg(feature = "api")] +pub use {client::AgdbApiClientDef, http_client::HttpClientDef}; diff --git a/agdb_derive/src/type_def_parser/trait_parser.rs b/agdb_derive/src/type_def_parser/trait_parser.rs index 48426d9f..f269ca3a 100644 --- a/agdb_derive/src/type_def_parser/trait_parser.rs +++ b/agdb_derive/src/type_def_parser/trait_parser.rs @@ -1,5 +1,7 @@ use crate::type_def_parser::function_parser; use crate::type_def_parser::generics_parser; +use proc_macro2::Ident; +use proc_macro2::Span; use proc_macro2::TokenStream as TokenStream2; use quote::quote; use syn::ItemTrait; @@ -7,13 +9,6 @@ use syn::TraitItem; pub(crate) fn parse_trait(input: &ItemTrait) -> TokenStream2 { let name_str = input.ident.to_string(); - let fn_name = crate::type_def_parser::type_def_fn(&name_str); - let lt_params = generics_parser::parse_lifetime_params(&input.generics); - let lt_generics = if lt_params.is_empty() { - quote! {} - } else { - quote! { <#(#lt_params),*> } - }; let generics = generics_parser::parse_generics(&input.generics); let bounds = input .supertraits @@ -35,14 +30,22 @@ pub(crate) fn parse_trait(input: &ItemTrait) -> TokenStream2 { _ => None, }); + let def_struct = Ident::new(&format!("{name_str}Def"), Span::call_site()); + let vis = &input.vis; + quote! { - fn #fn_name #lt_generics () -> ::agdb::type_def::Type { - ::agdb::type_def::Type::Trait(::agdb::type_def::Trait { - name: #name_str, - generics: &[#(#generics),*], - bounds: &[#(#bounds),*], - functions: &[#(#functions),*], - }) + #[allow(non_camel_case_types)] + #vis struct #def_struct; + + impl ::agdb::type_def::TypeDefinition for #def_struct { + fn type_def() -> ::agdb::type_def::Type { + ::agdb::type_def::Type::Trait(::agdb::type_def::Trait { + name: #name_str, + generics: &[#(#generics),*], + bounds: &[#(#bounds),*], + functions: &[#(#functions),*], + }) + } } } }