Skip to content

Commit

Permalink
implement kitsune-derive
Browse files Browse the repository at this point in the history
  • Loading branch information
aumetra committed May 9, 2024
1 parent 8586d06 commit 3eac046
Show file tree
Hide file tree
Showing 18 changed files with 241 additions and 381 deletions.
323 changes: 54 additions & 269 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ members = [
"crates/kitsune-config",
"crates/kitsune-core",
"crates/kitsune-db",
"crates/kitsune-derive",
"crates/kitsune-derive/impl",
"crates/kitsune-email",
"crates/kitsune-embed",
"crates/kitsune-error",
Expand Down
14 changes: 14 additions & 0 deletions crates/kitsune-derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "kitsune-derive"
authors.workspace = true
edition.workspace = true
version.workspace = true
license.workspace = true

[dependencies]
kitsune-derive-impl = { path = "impl" }
triomphe = "0.1.11"
typed-builder = "0.18.2"

[lints]
workspace = true
1 change: 1 addition & 0 deletions crates/kitsune-derive/LICENSE-AGPL-3.0
17 changes: 17 additions & 0 deletions crates/kitsune-derive/impl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "kitsune-derive-impl"
authors.workspace = true
edition.workspace = true
version.workspace = true
license.workspace = true

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0.82"
quote = "1.0.36"
syn = { version = "2.0.61", features = ["full"] }

[lints]
workspace = true
115 changes: 115 additions & 0 deletions crates/kitsune-derive/impl/src/expand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use std::iter;
use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
Token, Visibility,
};

struct Attributes {
expand_builder: bool,
}

impl Default for Attributes {
fn default() -> Self {
Self {
expand_builder: true,
}
}
}

impl Parse for Attributes {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let mut attributes = Self::default();
let punctuated = Punctuated::<syn::Ident, Token![,]>::parse_terminated(input)?;

for ident in punctuated {
if ident == "omit_builder" {
attributes.expand_builder = false;
} else {
return Err(syn::Error::new(
ident.span(),
format!("unknown attribute: {ident}"),
));

Check warning on line 35 in crates/kitsune-derive/impl/src/expand.rs

View check run for this annotation

Codecov / codecov/patch

crates/kitsune-derive/impl/src/expand.rs#L32-L35

Added lines #L32 - L35 were not covered by tests
}
}

Ok(attributes)
}
}

fn expand_builder(
parsed_struct: &syn::ItemStruct,
inner_struct_name: &syn::Ident,
) -> (TokenStream, TokenStream) {
let struct_name = &parsed_struct.ident;
let inner_builder_name = format_ident!("{inner_struct_name}Builder");

let num_lifetimes = parsed_struct.generics.lifetimes().count();
let lifetimes = iter::repeat(quote!('_)).take(num_lifetimes);

let attrs = quote! {
#[derive(::kitsune_derive::typed_builder::TypedBuilder)]
#[builder(build_method(into = #struct_name))]
};
let impls = quote! {
impl #struct_name {
pub fn builder() -> #inner_builder_name<#(#lifetimes),*> {
#inner_struct_name::builder()
}
}
};

Check warning on line 63 in crates/kitsune-derive/impl/src/expand.rs

View check run for this annotation

Codecov / codecov/patch

crates/kitsune-derive/impl/src/expand.rs#L43-L63

Added lines #L43 - L63 were not covered by tests

(attrs, impls)
}

Check warning on line 66 in crates/kitsune-derive/impl/src/expand.rs

View check run for this annotation

Codecov / codecov/patch

crates/kitsune-derive/impl/src/expand.rs#L65-L66

Added lines #L65 - L66 were not covered by tests

pub fn expand(attrs: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
let attributes = syn::parse2::<Attributes>(attrs)?;
let mut parsed_struct = syn::parse2::<syn::ItemStruct>(input)?;

let struct_name = parsed_struct.ident.clone();
let inner_struct_name = format_ident!("__{struct_name}__Inner");

let (builder_attrs, builder_impls) = if attributes.expand_builder {
expand_builder(&parsed_struct, &inner_struct_name)

Check warning on line 76 in crates/kitsune-derive/impl/src/expand.rs

View check run for this annotation

Codecov / codecov/patch

crates/kitsune-derive/impl/src/expand.rs#L76

Added line #L76 was not covered by tests
} else {
(TokenStream::new(), TokenStream::new())
};

parsed_struct.ident = inner_struct_name.clone();
parsed_struct.vis = Visibility::Public(Token![pub](parsed_struct.span()));

let output = quote! {
#builder_attrs
#[allow(non_camel_case_types)]
#[doc(hidden)]
#parsed_struct

#[derive(Clone)]
pub struct #struct_name {
inner: ::kitsune_derive::triomphe::Arc<#inner_struct_name>,
}

#builder_impls

impl ::core::ops::Deref for #struct_name {
type Target = #inner_struct_name;

fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl From<#inner_struct_name> for #struct_name {
fn from(inner: #inner_struct_name) -> Self {
Self {
inner: ::kitsune_derive::triomphe::Arc::new(inner),
}
}
}
};

Ok(output)
}
12 changes: 12 additions & 0 deletions crates/kitsune-derive/impl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
mod expand;

#[proc_macro_attribute]
pub fn kitsune_service(
attrs: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
match self::expand::expand(attrs.into(), input.into()) {
Ok(out) => out.into(),
Err(error) => error.to_compile_error().into(),

Check warning on line 10 in crates/kitsune-derive/impl/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/kitsune-derive/impl/src/lib.rs#L10

Added line #L10 was not covered by tests
}
}
3 changes: 3 additions & 0 deletions crates/kitsune-derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub use ::kitsune_derive_impl::kitsune_service;
pub use ::triomphe;
pub use ::typed_builder;
1 change: 1 addition & 0 deletions crates/kitsune-embed/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ embed-sdk = { git = "https://github.com/Lantern-chat/embed-service.git", rev = "
http = "1.1.0"
iso8601-timestamp = "0.2.17"
kitsune-db = { path = "../kitsune-db" }
kitsune-derive = { path = "../kitsune-derive" }
kitsune-error = { path = "../kitsune-error" }
kitsune-http-client = { path = "../kitsune-http-client" }
once_cell = "1.19.0"
Expand Down
1 change: 1 addition & 0 deletions crates/kitsune-embed/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use kitsune_db::{
schema::link_previews,
with_connection, PgPool,
};
use kitsune_derive::kitsune_service;
use kitsune_error::Result;
use kitsune_http_client::Client as HttpClient;
use once_cell::sync::Lazy;
Expand Down
1 change: 1 addition & 0 deletions crates/kitsune-federation-filter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ license.workspace = true
[dependencies]
globset = "0.4.14"
kitsune-config = { path = "../kitsune-config" }
kitsune-derive = { version = "0.0.1-pre.6", path = "../kitsune-derive" }
kitsune-error = { path = "../kitsune-error" }
kitsune-type = { path = "../kitsune-type" }
url = "2.5.0"
Expand Down
13 changes: 8 additions & 5 deletions crates/kitsune-federation-filter/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use globset::{Glob, GlobSet, GlobSetBuilder};
use kitsune_config::instance::FederationFilterConfiguration;
use kitsune_derive::kitsune_service;
use kitsune_error::{kitsune_error, Result};
use kitsune_type::ap::{actor::Actor, Activity, Object};
use std::sync::Arc;
use url::Url;

pub trait Entity {
Expand Down Expand Up @@ -33,9 +33,9 @@ enum FilterMode {
Deny,
}

#[derive(Clone)]
#[kitsune_service(omit_builder)]
pub struct FederationFilter {
domains: Arc<GlobSet>,
domains: GlobSet,
filter: FilterMode,
}

Expand All @@ -50,9 +50,12 @@ impl FederationFilter {
for glob in globs {
globset.add(Glob::new(glob)?);
}
let domains = Arc::new(globset.build()?);

Ok(Self { domains, filter })
Ok(__FederationFilter__Inner {
domains: globset.build()?,
filter,
}
.into())
}

pub fn is_url_allowed(&self, url: &Url) -> Result<bool> {
Expand Down
6 changes: 0 additions & 6 deletions crates/kitsune-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ redis = { version = "0.25.3", default-features = false, features = [
"tokio-rustls-comp",
] }
rusty-s3 = { version = "0.5.0", default-features = false }
testcontainers = "0.16.7"
testcontainers-modules = { version = "0.4.2", features = [
"minio",
"postgres",
"redis",
] }
tokio = { version = "1.37.0", features = ["time"] }
url = "2.5.0"
uuid = { version = "1.8.0", features = ["fast-rng", "v4"] }
Expand Down
56 changes: 0 additions & 56 deletions crates/kitsune-test/src/container.rs

This file was deleted.

15 changes: 7 additions & 8 deletions crates/kitsune-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ use kitsune_config::{
use kitsune_db::PgPool;
use multiplex_pool::RoundRobinStrategy;
use resource::provide_resource;
use std::sync::Arc;
use std::{env, sync::Arc};
use url::Url;
use uuid::Uuid;

mod catch_panic;
mod container;
mod macros;
mod redis;
mod resource;
Expand All @@ -37,8 +36,8 @@ where
F: FnOnce(PgPool) -> Fut,
Fut: Future,
{
let resource_handle = get_resource!("DATABASE_URL", self::container::postgres);
let mut url = Url::parse(&resource_handle.url().await).unwrap();
let db_url = env::var("DATABASE_URL").unwrap();
let mut url = Url::parse(&db_url).unwrap();

// Create a new separate database for this test
let id = Uuid::new_v4().as_simple().to_string();
Expand Down Expand Up @@ -84,8 +83,8 @@ where
F: FnOnce(Arc<kitsune_s3::Client>) -> Fut,
Fut: Future,
{
let resource_handle = get_resource!("MINIO_URL", self::container::minio);
let endpoint = resource_handle.url().await.parse().unwrap();
let endpoint = env::var("MINIO_URL").unwrap();
let endpoint = endpoint.parse().unwrap();

// Create a new bucket with a random ID
let bucket_id = Uuid::new_v4().as_simple().to_string();
Expand Down Expand Up @@ -116,8 +115,8 @@ where
F: FnOnce(multiplex_pool::Pool<ConnectionManager>) -> Fut,
Fut: Future,
{
let resource_handle = get_resource!("REDIS_URL", self::container::redis);
let client = ::redis::Client::open(resource_handle.url().await.as_ref()).unwrap();
let redis_url = env::var("REDIS_URL").unwrap();
let client = ::redis::Client::open(redis_url.as_ref()).unwrap();

// Connect to a random Redis database
let db_id = self::redis::find_unused_database(&client).await;
Expand Down
36 changes: 2 additions & 34 deletions crates/kitsune-test/src/resource.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,5 @@
use crate::{catch_panic::CatchPanic, container::Service};
use std::{borrow::Cow, future::Future, panic};

#[macro_export]
macro_rules! get_resource {
($env_name:literal, $container_fn:path) => {
if let Ok(url) = ::std::env::var($env_name) {
$crate::resource::ResourceHandle::Url(url)
} else {
let container = $container_fn().await;
$crate::resource::ResourceHandle::Container(container)
}
};
}

pub enum ResourceHandle<S>
where
S: Service,
{
Container(S),
Url(String),
}

impl<S> ResourceHandle<S>
where
S: Service,
{
pub async fn url(&self) -> Cow<'_, str> {
match self {
Self::Container(container) => Cow::Owned(container.url().await),
Self::Url(ref url) => Cow::Borrowed(url),
}
}
}
use crate::catch_panic::CatchPanic;
use std::{future::Future, panic};

/// Provide a resource to the `run` closure, catch any panics that may occur while polling the future returned by `run`,
/// then run the `cleanup` closure, and resume any panic unwinds that were caught
Expand Down
Loading

0 comments on commit 3eac046

Please sign in to comment.