diff --git a/Cargo.lock b/Cargo.lock index 8c7c9e8..1422567 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1405,6 +1405,7 @@ dependencies = [ "tower-http", "tracing", "tracing-subscriber", + "unicode-segmentation", ] [[package]] @@ -1490,6 +1491,7 @@ dependencies = [ "serde", "serde_json", "ts-rs", + "unicode-segmentation", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fea805b..7841d54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ tower-http = "0.4" tracing = "0.1" tracing-subscriber = "0.3" ts-rs = "6" +unicode-segmentation = "1.10" url = "2.3" walkdir = "2.3" wasm-bindgen = "0.2" @@ -95,5 +96,7 @@ serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } toml = { workspace = true } +unicode-segmentation = { workspace = true } + [profile.release] lto = true \ No newline at end of file diff --git a/magnetar_sdk/Cargo.toml b/magnetar_sdk/Cargo.toml index da0d5df..1e73f75 100644 --- a/magnetar_sdk/Cargo.toml +++ b/magnetar_sdk/Cargo.toml @@ -12,4 +12,6 @@ http = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } -ts-rs = { workspace = true, features = ["chrono", "chrono-impl"] } \ No newline at end of file +ts-rs = { workspace = true, features = ["chrono", "chrono-impl"] } + +unicode-segmentation = { workspace = true } \ No newline at end of file diff --git a/magnetar_sdk/src/endpoints/timeline.rs b/magnetar_sdk/src/endpoints/timeline.rs index 17e1f9c..8970416 100644 --- a/magnetar_sdk/src/endpoints/timeline.rs +++ b/magnetar_sdk/src/endpoints/timeline.rs @@ -22,7 +22,7 @@ fn default_timeline_limit() -> U64Range); #[derive(Endpoint)] diff --git a/magnetar_sdk/src/types/drive.rs b/magnetar_sdk/src/types/drive.rs index 87a8a93..49a8abd 100644 --- a/magnetar_sdk/src/types/drive.rs +++ b/magnetar_sdk/src/types/drive.rs @@ -9,7 +9,7 @@ use magnetar_sdk_macros::pack; use crate::types::Id; -#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[derive(Clone, Debug, Default, Deserialize, Serialize, TS)] #[ts(export)] pub struct ImageMeta { pub width: Option, @@ -49,9 +49,9 @@ pub struct DriveFileBase { pub name: String, pub created_at: DateTime, pub size: u64, - pub sha256: String, + pub hash: Option, pub mime_type: String, - pub image_meta: ImageMeta, + pub media_metadata: ImageMeta, pub url: Option, pub thumbnail_url: Option, pub sensitive: bool, diff --git a/magnetar_sdk/src/types/mod.rs b/magnetar_sdk/src/types/mod.rs index 09ec8c0..a3d7508 100644 --- a/magnetar_sdk/src/types/mod.rs +++ b/magnetar_sdk/src/types/mod.rs @@ -23,6 +23,12 @@ pub struct Id { pub id: String, } +impl From<&str> for Id { + fn from(id: &str) -> Self { + Self { id: id.to_string() } + } +} + #[derive(Copy, Clone, Debug, Deserialize, Serialize, TS)] #[ts(export)] pub enum NotificationType { diff --git a/magnetar_sdk/src/types/note.rs b/magnetar_sdk/src/types/note.rs index 233863e..e5e5dbb 100644 --- a/magnetar_sdk/src/types/note.rs +++ b/magnetar_sdk/src/types/note.rs @@ -1,5 +1,5 @@ use crate::types::emoji::EmojiContext; -use crate::types::user::{PackUserBase, UserBase}; +use crate::types::user::PackUserBase; use crate::types::Id; use crate::{Packed, Required}; use chrono::{DateTime, Utc}; @@ -56,7 +56,7 @@ pub struct NoteBase { pub url: Option, pub text: String, pub visibility: NoteVisibility, - pub user: Box, + pub user: Box, pub parent_note_id: Option, pub renoted_note_id: Option, pub reply_count: u64, @@ -65,6 +65,8 @@ pub struct NoteBase { pub reactions: Vec, pub emojis: EmojiContext, pub local_only: bool, + pub has_poll: bool, + pub file_ids: Vec, } pack!(PackNoteBase, Required as id & Required as note); @@ -73,7 +75,6 @@ pack!(PackNoteBase, Required as id & Required as note); #[ts(export)] pub struct NoteAttachmentExt { pub attachments: Vec, - pub poll: Option, } pack!( @@ -93,10 +94,28 @@ pack!( Required as id & Required as note & Required as attachment & Required as detail ); +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +pub enum Reaction { + Unicode(String), + Shortcode(String), +} + +impl Reaction { + pub fn guess_from(s: &str, default_emote: &str) -> Option { + let code = s.trim(); + match code.chars().next() { + Some(':') => Some(Reaction::Shortcode(code.to_string())), + Some(_) => Some(Reaction::Unicode(code.to_string())), + None => Self::guess_from(default_emote, "👍"), + } + } +} + #[derive(Clone, Debug, Deserialize, Serialize, TS)] pub struct ReactionBase { pub created_at: DateTime, pub user_id: String, + pub reaction: Reaction, } pack!(PackReactionBase, Required as id & Required as reaction); diff --git a/magnetar_sdk/src/types/user.rs b/magnetar_sdk/src/types/user.rs index f827e64..6ff7e53 100644 --- a/magnetar_sdk/src/types/user.rs +++ b/magnetar_sdk/src/types/user.rs @@ -5,10 +5,9 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use ts_rs::TS; +use crate::types::note::PackNoteFull; use magnetar_sdk_macros::pack; -use super::note::PackNoteWithAttachments; - #[derive(Clone, Debug, Default, Deserialize, Serialize, TS)] #[ts(export)] pub enum AvatarDecoration { @@ -85,7 +84,7 @@ pub struct UserProfileExt { #[derive(Clone, Debug, Deserialize, Serialize, TS)] #[ts(export)] pub struct UserProfilePinsEx { - pub pinned_notes: Vec, + pub pinned_notes: Vec, // pub pinned_page: Option, } diff --git a/src/model/data/drive.rs b/src/model/data/drive.rs index e267f8e..c994ae8 100644 --- a/src/model/data/drive.rs +++ b/src/model/data/drive.rs @@ -1,27 +1,26 @@ use magnetar_calckey_model::ck; -use magnetar_sdk::types::drive::DriveFileBase; +use magnetar_sdk::types::drive::{DriveFileBase, ImageMeta}; +use serde::Deserialize; -use crate::model::{PackBase, PackExtract, PackType, PackingContext}; +use crate::model::{PackType, PackingContext}; -impl PackType for PackExtract { - type Input = PackBase; +impl PackType<&ck::drive_file::Model> for DriveFileBase { + fn extract(_context: &PackingContext, file: &ck::drive_file::Model) -> Self { + let media_metadata = ImageMeta::deserialize(file.properties.clone()).unwrap_or_default(); - fn extract(context: &PackingContext, data: Self::Input) -> Self { - let PackBase(file) = data; - - PackExtract(DriveFileBase { - name: file.name, + DriveFileBase { + name: file.name.clone(), created_at: file.created_at.into(), size: file.size as u64, - sha256: todo!(), - mime_type: file.r#type, - image_meta: todo!(), - url: Some(file.url), - thumbnail_url: file.thumbnail_url, + hash: None, // TODO: blake3 + mime_type: file.r#type.clone(), + media_metadata, + url: Some(file.url.clone()), + thumbnail_url: file.thumbnail_url.clone(), sensitive: file.is_sensitive, - comment: file.comment, - folder_id: file.folder_id, - user_id: file.user_id, - }) + comment: file.comment.clone(), + folder_id: file.folder_id.clone(), + user_id: file.user_id.clone(), + } } } diff --git a/src/model/data/emoji.rs b/src/model/data/emoji.rs index 54cfe29..0d24e5f 100644 --- a/src/model/data/emoji.rs +++ b/src/model/data/emoji.rs @@ -1,19 +1,15 @@ -use crate::model::{PackBase, PackExtract, PackType, PackingContext}; +use crate::model::{PackType, PackingContext}; use magnetar_calckey_model::ck; use magnetar_sdk::types::emoji::EmojiBase; -impl PackType for PackExtract { - type Input = PackBase; - - fn extract(_context: &PackingContext, data: Self::Input) -> Self { - let PackBase(model) = data; - - PackExtract(EmojiBase { - shortcode: model.name.clone(), - category: model.category.clone(), - url: model.public_url.clone(), - width: model.width, - height: model.height, - }) +impl PackType<&ck::emoji::Model> for EmojiBase { + fn extract(_context: &PackingContext, emoji: &ck::emoji::Model) -> Self { + EmojiBase { + shortcode: emoji.name.clone(), + category: emoji.category.clone(), + url: emoji.public_url.clone(), + width: emoji.width, + height: emoji.height, + } } } diff --git a/src/model/data/note.rs b/src/model/data/note.rs index e39b728..f2fcf83 100644 --- a/src/model/data/note.rs +++ b/src/model/data/note.rs @@ -1,57 +1,54 @@ use magnetar_calckey_model::ck; +use magnetar_sdk::types::note::Reaction; +use magnetar_sdk::types::user::PackUserBase; use magnetar_sdk::types::{ drive::PackDriveFileBase, emoji::EmojiContext, note::{NoteAttachmentExt, NoteBase, NoteVisibility, PackReactionBase, ReactionBase}, user::UserBase, }; +use magnetar_sdk::{Packed, Required}; -use crate::model::{ - LinkAuto, PackAggregate, PackBase, PackChild, PackExtract, PackMulti, PackPacked, PackType, - PackingContext, -}; +use crate::model::{PackType, PackingContext}; -impl PackType for PackExtract { - type Input = PackBase; - - fn extract(_context: &PackingContext, data: Self::Input) -> Self { - let PackBase(reaction) = data; - - PackExtract(ReactionBase { +impl PackType<&ck::note_reaction::Model> for ReactionBase { + fn extract(context: &PackingContext, reaction: &ck::note_reaction::Model) -> Self { + ReactionBase { created_at: reaction.created_at.into(), - user_id: reaction.user_id, - }) + user_id: reaction.user_id.clone(), + reaction: Reaction::guess_from( + &reaction.reaction, + &context.instance_info.default_reaction, + ) + .unwrap_or_else(|| /* Shouldn't happen */ Reaction::Unicode("👍".to_string())), + } } } -impl PackType for PackExtract { - type Input = PackMulti<( - PackBase, - PackAggregate, LinkAuto>>, - PackChild, LinkAuto>, - PackChild, LinkAuto>, - )>; - - fn extract(_context: &PackingContext, data: Self::Input) -> Self { - let PackMulti(( - PackBase(note), - PackAggregate(reactions, ..), - PackChild(PackExtract(emojis), ..), - PackChild(PackExtract(user), ..), - )) = data; - - let reactions = reactions - .into_iter() - .map(|PackChild(PackPacked(t, ..), ..)| t) - .collect::>(); +pub struct NoteBaseSource<'a> { + pub note: &'a ck::note::Model, + pub reactions: &'a Vec, + pub emojis: &'a EmojiContext, + pub user: &'a UserBase, +} +impl PackType> for NoteBase { + fn extract( + _context: &PackingContext, + NoteBaseSource { + note, + reactions, + emojis, + user, + }: NoteBaseSource<'_>, + ) -> Self { use ck::sea_orm_active_enums::NoteVisibilityEnum as NVE; - PackExtract(NoteBase { + NoteBase { created_at: note.created_at.into(), - cw: note.cw, - uri: note.uri, - url: note.url, - text: note.text.unwrap_or_default(), + cw: note.cw.clone(), + uri: note.uri.clone(), + url: note.url.clone(), + text: note.text.clone().unwrap_or_default(), visibility: match note.visibility { NVE::Followers => NoteVisibility::Followers, NVE::Hidden => NoteVisibility::Direct, @@ -59,29 +56,28 @@ impl PackType for PackExtract { NVE::Home => NoteVisibility::Home, NVE::Specified => NoteVisibility::Direct, }, - user: Box::new(user), - parent_note_id: note.reply_id, - renoted_note_id: note.renote_id, + user: Box::new(PackUserBase::pack_from(( + Required(note.user_id.as_str().into()), + Required(user.clone()), + ))), + parent_note_id: note.reply_id.clone(), + renoted_note_id: note.renote_id.clone(), reply_count: note.replies_count as u64, renote_count: note.renote_count as u64, - hashtags: note.tags, - reactions, - emojis, + hashtags: note.tags.clone(), + reactions: reactions.clone(), + emojis: emojis.clone(), local_only: note.local_only, - }) + has_poll: note.has_poll, + file_ids: note.file_ids.clone(), + } } } -impl PackType for PackExtract { - type Input = PackMulti<( - PackBase, - PackAggregate, LinkAuto>>, - )>; - - fn extract(_context: &PackingContext, data: Self::Input) -> Self { - PackExtract(NoteAttachmentExt { - attachments: todo!(), - poll: todo!(), - }) +impl PackType<&Vec> for NoteAttachmentExt { + fn extract(_context: &PackingContext, data: &Vec) -> Self { + NoteAttachmentExt { + attachments: data.clone(), + } } } diff --git a/src/model/data/user.rs b/src/model/data/user.rs index 7b498e0..5975976 100644 --- a/src/model/data/user.rs +++ b/src/model/data/user.rs @@ -1,60 +1,29 @@ use magnetar_calckey_model::ck; use magnetar_calckey_model::ck::sea_orm_active_enums::UserProfileFfvisibilityEnum; use magnetar_sdk::types::emoji::{EmojiContext, PackEmojiBase}; -use magnetar_sdk::types::note::PackNoteWithAttachments; +use magnetar_sdk::types::note::PackNoteFull; use magnetar_sdk::types::user::{ AvatarDecoration, PackSecurityKeyBase, SecurityKeyBase, SpeechTransform, UserBase, UserDetailExt, UserProfileExt, UserProfilePinsEx, UserRelationExt, UserSecretsExt, }; -use crate::model::{ - LinkAuto, LinkIdent, PackAggregate, PackBase, PackChild, PackExtract, PackMaybe, PackMulti, - PackPacked, PackType, PackingContext, -}; +use crate::model::{PackType, PackingContext}; -impl PackType for PackExtract { - type Input = PackMulti<( - PackBase, - PackChild>, LinkAuto>, - )>; - - fn extract(_context: &PackingContext, data: Self::Input) -> Self { - let PackMulti((PackBase(_), PackChild(PackAggregate(emojis), ..))) = data; - - PackExtract(EmojiContext( - emojis - .into_iter() - .map(|PackPacked(t, ..)| t) - .collect::>(), - )) +impl PackType<&[PackEmojiBase]> for EmojiContext { + fn extract(_context: &PackingContext, data: &[PackEmojiBase]) -> Self { + EmojiContext(data.to_owned()) } } -#[derive(Copy, Clone, Debug, Default)] -pub struct UserAvatarLink; -impl From for LinkIdent { - fn from(_: UserAvatarLink) -> Self { - LinkIdent::Named("avatar".to_string()) - } -} +type UserBaseSource<'a> = ( + &'a ck::user::Model, + &'a Option, + &'a EmojiContext, +); -impl PackType for PackExtract { - type Input = PackMulti<( - PackBase, - PackChild>, UserAvatarLink>, - PackChild, LinkAuto>, - )>; - - fn extract(_context: &PackingContext, data: Self::Input) -> Self { - let PackMulti(( - PackBase(ref user), - PackChild(PackMaybe(ref avatar), _), - PackChild(PackExtract(ref emoji_context), _), - )) = data; - - let avatar = avatar.as_ref().map(|PackBase(v)| v); - - PackExtract(UserBase { +impl PackType> for UserBase { + fn extract(_context: &PackingContext, (user, avatar, emoji_context): UserBaseSource) -> Self { + UserBase { acct: user .host .as_ref() @@ -69,8 +38,8 @@ impl PackType for PackExtract { SpeechTransform::None }, created_at: user.created_at.into(), - avatar_url: avatar.map(|v| v.url.clone()), - avatar_blurhash: avatar.and_then(|v| v.blurhash.clone()), + avatar_url: avatar.as_ref().map(|v| v.url.clone()), + avatar_blurhash: avatar.as_ref().and_then(|v| v.blurhash.clone()), avatar_color: None, avatar_decoration: if user.is_cat { AvatarDecoration::CatEars @@ -81,35 +50,25 @@ impl PackType for PackExtract { is_moderator: user.is_moderator, is_bot: user.is_bot, emojis: emoji_context.clone(), - }) + } } } -impl PackType for PackExtract { - type Input = PackMulti<( - PackBase, - PackChild, LinkAuto>, - PackMaybe>, - )>; - - fn extract(context: &PackingContext, data: Self::Input) -> Self { - let PackMulti(( - PackBase(ref user), - PackChild(PackBase(ref profile), ..), - PackMaybe(ref relation), - )) = data; - - let relation = relation.as_ref().map(|PackExtract(v)| v); +type UserProfileExtSource<'a> = ( + &'a ck::user::Model, + &'a ck::user_profile::Model, + Option<&'a UserRelationExt>, +); +impl PackType> for UserProfileExt { + fn extract(context: &PackingContext, (user, profile, relation): UserProfileExtSource) -> Self { let follow_visibility = match profile.ff_visibility { UserProfileFfvisibilityEnum::Public => true, - UserProfileFfvisibilityEnum::Followers => { - relation.as_ref().is_some_and(|r| r.follows_you) - } + UserProfileFfvisibilityEnum::Followers => relation.is_some_and(|r| r.follows_you), UserProfileFfvisibilityEnum::Private => false, } || context.is_self(user); - PackExtract(UserProfileExt { + UserProfileExt { is_locked: user.is_locked, is_silenced: user.is_silenced, is_suspended: user.is_suspended, @@ -130,131 +89,96 @@ impl PackType for PackExtract { banner_color: None, banner_blurhash: None, has_public_reactions: profile.public_reactions, - }) + } } } -impl PackType for PackExtract { - type Input = PackBase; - - fn extract(_context: &PackingContext, data: Self::Input) -> Self { - let PackBase(model) = data; - - PackExtract(UserDetailExt { - last_fetched_at: model.last_fetched_at.map(Into::into), - uri: model.uri.clone(), - updated_at: model.updated_at.map(Into::into), - }) +impl PackType<&ck::user::Model> for UserDetailExt { + fn extract(_context: &PackingContext, user: &ck::user::Model) -> Self { + UserDetailExt { + last_fetched_at: user.last_fetched_at.map(Into::into), + uri: user.uri.clone(), + updated_at: user.updated_at.map(Into::into), + } } } -impl PackType for PackExtract { - type Input = PackMulti<( - PackChild, LinkAuto>, - PackChild, LinkAuto>, - PackChild, LinkAuto>, - PackChild, LinkAuto>, - )>; - - fn extract(context: &PackingContext, data: Self::Input) -> Self { - let PackMulti(( - PackChild(PackBase(ref follow), ..), - PackChild(PackBase(ref block), ..), - PackChild(PackBase(ref mute), ..), - PackChild(PackBase(ref renote_mute), ..), - )) = data; +type UserRelationExtSource<'a> = ( + Option<&'a ck::following::Model>, + Option<&'a ck::following::Model>, + Option<&'a ck::blocking::Model>, + Option<&'a ck::blocking::Model>, + Option<&'a ck::muting::Model>, + Option<&'a ck::renote_muting::Model>, +); +impl PackType> for UserRelationExt { + fn extract( + context: &PackingContext, + (follow_out, follow_in, block_out, block_in, mute, renote_mute): UserRelationExtSource, + ) -> Self { let self_user = context.self_user(); - PackExtract(UserRelationExt { + UserRelationExt { follows_you: self_user.is_some_and(|self_user| { - self_user.id == follow.followee_id && self_user.id != follow.follower_id + follow_in.is_some_and(|follow_in| { + self_user.id == follow_in.followee_id && self_user.id != follow_in.follower_id + }) }), you_follow: self_user.is_some_and(|self_user| { - self_user.id == follow.follower_id && self_user.id != follow.followee_id + follow_out.is_some_and(|follow_out| { + self_user.id == follow_out.follower_id && self_user.id != follow_out.followee_id + }) }), blocks_you: self_user.is_some_and(|self_user| { - self_user.id == block.blockee_id && self_user.id != block.blocker_id + block_in.is_some_and(|block_in| { + self_user.id == block_in.blockee_id && self_user.id != block_in.blocker_id + }) }), you_block: self_user.is_some_and(|self_user| { - self_user.id == block.blocker_id && self_user.id != block.blockee_id + block_out.is_some_and(|block_out| { + self_user.id == block_out.blocker_id && self_user.id != block_out.blockee_id + }) }), mute: self_user.is_some_and(|self_user| { - self_user.id == mute.muter_id && self_user.id != mute.mutee_id + mute.is_some_and(|mute| { + self_user.id == mute.muter_id && self_user.id != mute.mutee_id + }) }), mute_renotes: self_user.is_some_and(|self_user| { - self_user.id == renote_mute.muter_id && self_user.id != renote_mute.mutee_id + renote_mute.is_some_and(|renote_mute| { + self_user.id == renote_mute.muter_id && self_user.id != renote_mute.mutee_id + }) }), - }) + } } } -impl PackType for PackExtract { - type Input = PackMulti<( - PackBase, - PackChild< - PackAggregate< - PackMulti<( - PackBase, - PackChild, LinkAuto>, - )>, - >, - LinkAuto, - >, - )>; - - fn extract(_context: &PackingContext, data: Self::Input) -> Self { - let PackMulti((PackBase(_), PackChild(PackAggregate(pins), ..))) = data; - - PackExtract(UserProfilePinsEx { - pinned_notes: pins - .into_iter() - .map(|PackMulti((_, PackChild(PackPacked(note, ..), ..)))| note) - .collect(), - }) +impl PackType<&[PackNoteFull]> for UserProfilePinsEx { + fn extract(_context: &PackingContext, pinned_notes: &[PackNoteFull]) -> Self { + UserProfilePinsEx { + pinned_notes: pinned_notes.to_owned(), + } } } -impl PackType for PackExtract { - type Input = PackBase; - - fn extract(_context: &PackingContext, data: Self::Input) -> Self { - let PackBase(model) = data; - - PackExtract(SecurityKeyBase { - name: model.name.clone(), - last_used_at: Some(model.last_used.into()), - }) +impl PackType for SecurityKeyBase { + fn extract(_context: &PackingContext, key: ck::user_security_key::Model) -> Self { + SecurityKeyBase { + name: key.name.clone(), + last_used_at: Some(key.last_used.into()), + } } } -impl PackType for PackExtract { - type Input = PackMulti<( - PackBase, - PackChild< - PackMulti<( - PackBase, - PackChild>, LinkAuto>, - )>, - LinkAuto, - >, - )>; +type UserSecretsExtSource<'a> = (&'a ck::user_profile::Model, &'a [PackSecurityKeyBase]); - fn extract(_context: &PackingContext, data: Self::Input) -> Self { - let PackMulti(( - _, - PackChild(PackMulti((PackBase(ref profile), PackChild(PackAggregate(keys), ..))), ..), - )) = data; - - let keys = keys - .into_iter() - .map(|PackPacked(t, ..)| t) - .collect::>(); - - PackExtract(UserSecretsExt { +impl PackType> for UserSecretsExt { + fn extract(_context: &PackingContext, (profile, keys): UserSecretsExtSource) -> Self { + UserSecretsExt { email: profile.email.clone(), email_verified: profile.email_verified, - security_keys: keys.clone(), - }) + security_keys: keys.to_owned(), + } } } diff --git a/src/model/db_pack/mod.rs b/src/model/db_pack/mod.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/model/map_type.rs b/src/model/map_type.rs deleted file mode 100644 index 449f86f..0000000 --- a/src/model/map_type.rs +++ /dev/null @@ -1,163 +0,0 @@ -use crate::model::LinkIdent; -use std::any::TypeId; -use std::fmt::Debug; -use std::sync::Arc; - -type PMT = PackMapType; - -#[derive(Clone, Debug)] -pub struct Multi(Vec>); - -impl Multi { - pub fn get_base(&self) -> Option<&PMT> { - for pmt in &self.0 { - match pmt.as_ref() { - PackMapType::FromType(CommandPackFromType { base: true, .. }) => return Some(pmt), - PackMapType::Maybe(CommandPackMaybe { inner }) => { - if let PackMapType::FromType(..) = inner.as_ref() { - return Some(pmt); - } - } - PackMapType::Multi(CommandPackMulti { inner }) => { - if let Some(pmt) = inner.get_base() { - return Some(pmt); - } - } - _ => {} - } - } - - None - } -} - -impl From> for Multi { - fn from(v: Vec) -> Self { - Multi(v.into_iter().map(Arc::new).collect()) - } -} - -#[derive(Clone, Debug)] -pub enum PackMapType { - FromType(CommandPackFromType), - Maybe(CommandPackMaybe), - Child(CommandPackChild), - Aggregate(CommandPackAggregate), - Multi(CommandPackMulti), -} - -trait PackCommand {} - -#[derive(Clone, Debug)] -pub struct CommandPackFromType { - pub name: String, - pub id: TypeId, - pub base: bool, -} - -impl PackCommand for CommandPackFromType {} - -#[derive(Clone, Debug)] -pub struct CommandPackMaybe { - pub inner: Arc, -} - -impl PackCommand for CommandPackMaybe {} - -#[derive(Clone, Debug)] -pub struct CommandPackChild { - pub inner: Arc, - pub link: LinkIdent, -} - -impl PackCommand for CommandPackChild {} - -#[derive(Clone, Debug)] -pub struct CommandPackAggregate { - pub inner: Arc, -} - -impl PackCommand for CommandPackAggregate {} - -#[derive(Clone, Debug)] -pub struct CommandPackMulti { - pub inner: Multi, -} - -impl PackCommand for CommandPackMulti {} - -impl PackMapType { - pub fn from_type(base: bool) -> Self { - PackMapType::FromType(CommandPackFromType { - name: std::any::type_name::().to_string(), - id: TypeId::of::(), - base, - }) - } - - pub fn get_base_type(&self) -> TypeId { - let id = match self { - PackMapType::FromType(CommandPackFromType { base: true, .. }) => Some(self), - PackMapType::Multi(CommandPackMulti { inner }) => inner.get_base(), - _ => None, - }; - - let PackMapType::FromType(CommandPackFromType { id, .. }) = id.expect("no base type") else { - panic!("base type is not FromType") - }; - - *id - } - - pub fn as_edges( - &self, - base_parent: &Option<(usize, String)>, - parent: &Option<(usize, String)>, - level: usize, - ) -> Vec<(Option, String)> { - match self { - PackMapType::FromType(CommandPackFromType { - name, base: true, .. - }) => { - vec![(base_parent.clone().map(|(_, s)| s), name.clone())] - } - PackMapType::FromType(CommandPackFromType { - name, base: false, .. - }) => { - vec![(parent.clone().map(|(_, s)| s), name.clone())] - } - PackMapType::Maybe(CommandPackMaybe { inner }) => { - inner.as_edges(base_parent, parent, level) - } - PackMapType::Aggregate(CommandPackAggregate { inner }) => { - inner.as_edges(base_parent, parent, level) - } - PackMapType::Child(CommandPackChild { inner, .. }) => { - inner.as_edges(parent, &None, level + 1) - } - PackMapType::Multi(CommandPackMulti { inner }) => { - let new_parent = if let Some(PackMapType::FromType(CommandPackFromType { - name, - base: true, - .. - })) = inner.get_base() - { - if parent.clone().is_some_and(|(l, _)| l == level) { - parent.clone() - } else { - Some((level, name.clone())) - } - } else { - parent.clone() - }; - - let mut edges = Vec::new(); - for t in &inner.0 { - edges.extend(t.as_edges(base_parent, &new_parent, level)); - } - - edges - } - } - } -} diff --git a/src/model/mod.rs b/src/model/mod.rs index aa65374..031dbaf 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -1,356 +1,21 @@ -use crate::model::map_type::{ - CommandPackAggregate, CommandPackChild, CommandPackMaybe, CommandPackMulti, PackMapType, -}; use magnetar_calckey_model::ck; -use magnetar_sdk::types::Id; -use magnetar_sdk::{Packed, Required}; -use std::marker::PhantomData; use std::sync::Arc; -use self::data::id::BaseId; - pub mod data; -pub mod db_pack; -pub mod map_type; #[derive(Clone, Debug)] -struct InternalContext { +pub struct PackingContext { + instance_info: Arc, self_user: Option>, } -#[derive(Clone, Debug)] -pub struct PackingContext { - context: Arc, - data: Arc, - _type: PhantomData, +pub trait PackType: 'static { + fn extract(context: &PackingContext, data: I) -> Self; } -impl PackingContext { - fn cloned(&self) -> PackingContext { - PackingContext { - context: self.context.clone(), - data: self.data.clone(), - _type: PhantomData, - } - } -} - -pub trait ReportType: 'static { - type Input: 'static; - - fn report_type() -> PackMapType; -} - -pub trait PackType: 'static { - type Input: 'static; - - fn extract(context: &PackingContext, data: Self::Input) -> Self; - - fn is_base_type() -> bool { - false - } -} - -#[derive(Clone, Debug)] -pub struct PackExtract(T); - -impl ReportType for PackExtract -where - Self: PackType, - ::Input: ReportType + PackType, -{ - type Input = ::Input; - - fn report_type() -> PackMapType { - ::Input::report_type() - } -} - -#[derive(Clone, Debug)] -pub enum LinkIdent { - Auto, - Named(String), -} - -#[derive(Copy, Clone, Debug, Default)] -pub struct LinkAuto; - -impl From for LinkIdent { - fn from(_: LinkAuto) -> Self { - LinkIdent::Auto - } -} - -// Raw input type children -#[derive(Clone, Debug)] -pub struct PackBase(T); - -impl ReportType for PackBase { - type Input = In; - - fn report_type() -> PackMapType { - PackMapType::from_type::(true) - } -} - -impl PackType for PackBase { - type Input = In; - - fn extract(_context: &PackingContext, data: ::Input) -> Self { - PackBase(data) - } - - fn is_base_type() -> bool { - true - } -} - -// Raw input type children, non-base -#[derive(Clone, Debug)] -pub struct PackExt(T); - -impl ReportType for PackExt { - type Input = In; - - fn report_type() -> PackMapType { - PackMapType::from_type::(false) - } -} - -impl PackType for PackExt { - type Input = In; - - fn extract(_context: &PackingContext, data: ::Input) -> Self { - PackExt(data) - } -} - -// Tree children -#[derive(Clone, Debug)] -pub struct PackChild + Default + 'static>( - T, - PhantomData L>, -); - -impl + Default + 'static> ReportType - for PackChild -{ - type Input = In; - - fn report_type() -> PackMapType { - PackMapType::Child(CommandPackChild { - inner: Arc::new(In::report_type()), - link: L::into(L::default()), - }) - } -} - -impl + Default + 'static> PackType - for PackChild -{ - type Input = In; - - fn extract(_context: &PackingContext, data: ::Input) -> Self { - PackChild(data, PhantomData) - } -} - -// Aggregate multiple entries 1:N -#[derive(Clone, Debug)] -pub struct PackAggregate(Vec); - -impl ReportType for PackAggregate { - type Input = In; - - fn report_type() -> PackMapType { - PackMapType::Aggregate(CommandPackAggregate { - inner: Arc::new(In::report_type()), - }) - } -} - -impl PackType for PackAggregate { - type Input = Vec; - - fn extract(_context: &PackingContext, data: ::Input) -> Self { - PackAggregate(data) - } -} - -// An item that may or may not be present -#[derive(Clone, Debug)] -pub struct PackMaybe(Option); - -impl ReportType for PackMaybe { - type Input = In; - - fn report_type() -> PackMapType { - In::report_type() - } -} - -impl PackType for PackMaybe { - type Input = Option; - - fn extract(_context: &PackingContext, data: ::Input) -> Self { - PackMaybe(data) - } -} - -// Multiple adjacent values -#[derive(Clone, Debug)] -pub struct PackMulti(T); - -macro_rules! impl_pack_multi { - ($($a:ident as $b:ident),*) => { - impl<$($a,)*> ReportType for PackMulti<($($a,)*)> - where $($a: ReportType + PackType,)* { - type Input = ($(<$a as ReportType>::Input,)*); - - fn report_type() -> PackMapType { - PackMapType::Multi(CommandPackMulti { - inner: vec![$( - $a::report_type(), - )*].into(), - }) - } - } - - impl<$($a,)*> PackType for PackMulti<($($a,)*)> - where $($a: ReportType + PackType,)* { - type Input = ($(<$a as PackType>::Input,)*); - - fn extract(context: &PackingContext, ($($b,)*): ::Input) -> Self { - PackMulti(($( - <$a as PackType>::extract(&context.cloned(), $b), - )*)) - } - } - }; -} - -impl_pack_multi!(); -impl_pack_multi!(A as a); -impl_pack_multi!(A as a, B as b); -impl_pack_multi!(A as a, B as b, C as c); -impl_pack_multi!(A as a, B as b, C as c, D as d); -impl_pack_multi!(A as a, B as b, C as c, D as d, E as e); -impl_pack_multi!(A as a, B as b, C as c, D as d, E as e, F as f); -impl_pack_multi!(A as a, B as b, C as c, D as d, E as e, F as f, G as g); -impl_pack_multi!(A as a, B as b, C as c, D as d, E as e, F as f, G as g, H as h); - -// API packed types - -pub struct PackPacked::Input>(T, PhantomData); - -macro_rules! impl_pack_raw_tuple { - ($($a:ident),*) => { - impl<$($a,)* P: Packed> ReportType for PackPacked - where $(PackWrapper<$a>: ReportType + PackType),* { - type Input = ($($a,)*); - - fn report_type() -> PackMapType { - PackMapType::Multi(CommandPackMulti { - inner: vec![ - $( - PackWrapper::<$a>::report_type() - ),* - ].into() - }) - } - } - - impl<$($a,)* P: Packed> PackType for PackPacked - where $(PackWrapper<$a>: ReportType + PackType),* { - type Input = ($($a,)*); - - fn extract(_context: &PackingContext, data: ::Input) -> Self { - PackPacked(P::pack_from(data), PhantomData) - } - } - }; -} - -impl_pack_raw_tuple!(A); -impl_pack_raw_tuple!(A, B); -impl_pack_raw_tuple!(A, B, C); -impl_pack_raw_tuple!(A, B, C, D); -impl_pack_raw_tuple!(A, B, C, D, E); -impl_pack_raw_tuple!(A, B, C, D, E, F); -impl_pack_raw_tuple!(A, B, C, D, E, F, G); -impl_pack_raw_tuple!(A, B, C, D, E, F, G, H); - -// Helper wrapper for Multi components -#[derive(Clone, Debug)] -pub struct PackWrapper(T); - -impl ReportType for PackWrapper> -where - PackExtract: ReportType + PackType, -{ - type Input = as ReportType>::Input; - - fn report_type() -> PackMapType { - PackExtract::::report_type() - } -} - -impl PackType for PackWrapper> -where - PackExtract: ReportType + PackType, -{ - type Input = as PackType>::Input; - - fn extract(context: &PackingContext, data: Self::Input) -> Self { - PackWrapper(Required( - PackExtract::::extract(&context.cloned(), data).0, - )) - } -} - -impl ReportType for PackWrapper> -where - PackExtract: ReportType + PackType, -{ - type Input = In; - - fn report_type() -> PackMapType { - PackMapType::Maybe(CommandPackMaybe { - inner: Arc::new(PackExtract::::report_type()), - }) - } -} - -impl PackType for PackWrapper> -where - PackExtract: ReportType + PackType, -{ - type Input = Option; - - fn extract(context: &PackingContext, data: Self::Input) -> Self { - PackWrapper( - PackMaybe::>::extract(&context.cloned(), data.map(PackExtract)) - .0 - .map(|PackExtract(x)| x), - ) - } -} - -// Concrete extractable types -impl PackType for PackExtract { - type Input = PackExt>; - - fn extract(_context: &PackingContext, PackExt(data): ::Input) -> Self { - PackExtract(Id { - id: data.get_id().to_owned(), - }) - } -} - -// Packing context that gets passed in -impl PackingContext { +impl PackingContext { fn self_user(&self) -> Option<&ck::user::Model> { - self.context.self_user.as_deref() + self.self_user.as_deref() } fn is_self(&self, user: &ck::user::Model) -> bool { @@ -358,37 +23,3 @@ impl PackingContext { .is_some_and(|self_user| self_user.id == user.id) } } - -pub struct Packer { - context: PackingContext, -} - -pub fn pack_from_db( - self_user: Option>, -) -> Packer { - let types = T::report_type(); - let context = PackingContext { - context: Arc::new(InternalContext { self_user }), - data: Arc::new(types), - _type: PhantomData, - }; - - Packer { context } -} - -#[cfg(test)] -mod tests { - use super::*; - use magnetar_sdk::types::user::PackUserSelfMaybeAll; - - #[test] - fn test_pack_type() { - let types = as ReportType>::report_type(); - println!("{:?}", types); - - let edges = types.as_edges(&None, &None, 0); - for (from, to) in edges { - println!("{:?} --> {:?}", from, to); - } - } -}