Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Events Handling (#1) #2

Merged
merged 42 commits into from
Aug 30, 2021
Merged

Implement Events Handling (#1) #2

merged 42 commits into from
Aug 30, 2021

Conversation

ilslv
Copy link
Member

@ilslv ilslv commented Aug 13, 2021

Part of #1

Synopsis

Firstly we should implement abstractions for Events

Solution

  • Traits
    • Event
    • VersionedEvent
    • EventSourced
    • EventInitialised
  • Structs
    • InitialEvent wrapper
  • Proc macros
    • Event derive
    • VersionedEvent derive
  • Toolchain
    • Makefile
    • PR and Issue templates
    • GitHub Actions CI

Checklist

  • Created PR:
    • In draft mode
    • Name contains Draft: prefix
    • Name contains issue reference
    • Has k:: labels applied
    • Has assignee
  • Documentation is updated (if required)
  • Tests are updated (if required)
  • Changes conform code style
  • CHANGELOG entry is added (if required)
  • FCM (final commit message) is posted
    • and approved
  • Review is completed and changes are approved
  • Before merge:
    • Milestone is set
    • PR's name and description are correct and up-to-date
    • Draft: prefix is removed
    • All temporary labels are removed

@ilslv ilslv added feature New feature or request k::design Related to overall design and/or architecture k::toolchain Related to project toolchain labels Aug 13, 2021
@ilslv ilslv added this to the 0.1.0 milestone Aug 13, 2021
@ilslv ilslv self-assigned this Aug 13, 2021
@ilslv ilslv changed the title Draft: Implement Events Handling #1 Draft: Implement Events Handling (#1) Aug 13, 2021
@ilslv
Copy link
Member Author

ilslv commented Aug 17, 2021

FCM

Implement Events Handling (#1, #2)

- Traits
  - Event
  - VersionedEvent
  - EventSourced
  - EventInitialised
- Structs
  - InitialEvent wrapper
  - EventVersion
- Proc macros
  - Event derive
  - VersionedEvent derive
- Toolchain
  - Makefile
  - GitHub Actions CI

@ilslv ilslv requested review from tyranron and removed request for tyranron August 17, 2021 08:37
Copy link
Member

@tyranron tyranron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ilslv will discuss stuff additionally in videocall.

///
/// _Note:_ This should effectively be a constant value, and should never
/// change.
fn event_type(&self) -> &'static str;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change it to name. Termin type here was borrowed from other implementations, but tends to make more confusion. With name we have a clear separation when we're saying "event name" and "event type".

core/src/lib.rs Outdated
unused_results
)]

mod event;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's hide it behind es (event sourcing) feature gate.

# Testing #
###########

test:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also let's add tests for MSRV (minimum supported Rust version) from the start.

/// Wrapper-type intended for [`Event`]s that can initialize [`Sourced`] items.
#[derive(Debug, RefCast)]
#[repr(transparent)]
pub struct Initial<Ev: ?Sized>(pub Ev);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clone, Copy and transparent Display would be useful as well.

#[repr(transparent)]
pub struct Initial<Ev: ?Sized>(pub Ev);

impl<Ev: Event + ?Sized, Agg: Initialized<Ev>> Sourced<Initial<Ev>>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to use S and "state" terminology here than "aggregate" as more general.

core/src/lib.rs Outdated
#[doc(inline)]
pub use event::{
Event, Initial as InitialEvent, Initialized as EventInitialized,
Sourced as EventSourced, Versioned as VersionedEvent,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And let's call the module es (event sourcing).


use super::MAX_UNIQUE_EVENTS;

/// Derives `arcana::VersionedEvent` for struct.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use links to arcana-core crate. The crates layout allows it.

ident: syn::Ident,
generics: syn::Generics,
event_type: syn::LitStr,
event_ver: syn::LitInt,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These fields should have documantation.

r#type: Option<syn::LitStr>,

#[parse(value)]
version: Option<syn::LitInt>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to see Attrs defined before Definition, following parse -> generate intuitive logic.

src/private.rs Outdated
pub const fn all_unique<const N: usize>(
types: [Option<(&str, u16)>; N],
) -> bool {
const fn str_eq(l: &str, r: &str) -> bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's OK for this function to be outside.

@tyranron tyranron removed the k::toolchain Related to project toolchain label Aug 17, 2021
Copy link
Member

@tyranron tyranron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ilslv still, discussion is required.

src/private.rs Outdated

#[doc(hidden)]
#[must_use]
const fn str_eq(l: &str, r: &str) -> bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No #[doc(hidden)]. Describe it. And an appropriate // TODO: for future removal.

@@ -80,8 +79,8 @@ impl Version {
}

impl<Ev: Versioned> Event for Ev {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?Sized here.

src/private.rs Outdated
#[doc(hidden)]
#[macro_export]
macro_rules! unique_event_type_and_ver_for_struct {
($max_events:literal, $event_type:literal, $event_ver:literal) => {
macro_rules! unique_event_name_and_ver_for_struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This macros better move to proc-macro machinery. There is no point to generate a half of an implementation via declarative and another part via proc macros. Better to keep things in a single place asap.

@ilslv ilslv requested a review from tyranron August 23, 2021 06:59
Copy link
Member

@tyranron tyranron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed.

_ => {
return Err(syn::Error::new_spanned(
input,
"`name` and `version` arguments expected",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have synthez::Required for that.


impl #impl_generics #name #ty_generics #where_clause {
#[automatically_derived]
pub const fn __arcana_events() -> [(&'static str, u16); 1] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to hide such inner machinery from docs via #[doc(hidden)].


assert_eq!(
format!("{}", err),
"either `version` or `ver` argument of `#[event]` attribute is \
Copy link
Member Author

@ilslv ilslv Aug 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tyranron it looks like error message isn't deterministic. Sometimes I get either 'ver' or 'version' argument of '#[event]' attribute is expected to be present, but is absent, so ver and version are switched (even on 2 CI runs (first, second) for the same code different jobs failed). As I understand this happens because synthez uses HashSet<syn::Ident> under the hood. HashSet docs are saying that there is requirement

k1 == k2 -> hash(k1) == hash(k2)

And for syn::Ident that promise isn't held up as I understand. PartialEq impl compares ident itself and it's Span, while Hash impl simply hashes ident, ignoring it's Span. This can be easily fixed specifically for error message generation, but I'm not sure if this thing can cause bigger ploblems.

Copy link
Member

@tyranron tyranron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've accidentally started reviewing it without realizing it's still wip. Review and consider my changes.

readme = "README.md"

[dependencies]
arcana-core = { version = "0.1.0-dev", path = "../../core", features = ["es"] }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't bloat dependencies with unused ones. If it's required for docs, let's introduce an appropriate feature, disabled by default.


::arcana::codegen::sa::const_assert!(
!::arcana::codegen::unique_events::has_duplicates(
#name::__arcana_events()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That simply won't work with generics.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tyranron it looks like there is no way to make it work with generics for now 😔
With your solution compiler error is

can't use generic parameters from outer function E0401
use of generic parameter from outer function

@ilslv ilslv requested a review from tyranron August 26, 2021 07:23
@tyranron tyranron changed the title Draft: Implement Events Handling (#1) Implement Events Handling (#1) Aug 30, 2021
@tyranron tyranron marked this pull request as ready for review August 30, 2021 10:59
Copy link
Member

@tyranron tyranron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FCM

Provide basic events sourcing (#2, #1)

- bootstrap project structure

Additionally:
- bootstrap CI pipeline
- bootstrap Makefile

/// #[derive(Event)]
/// enum DuplicatedEvent {
/// Any(AnyEvent),
/// File(FileEvent),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ilslv it seems that exactly this situation should be legit.

I guess it should be allowed to use the same event type multiple times. This allows us easily to merge sets of events.

What should be forbidden really - is using the same event_name + event_ver pair in different Rust types.

Let's merge this PR as it is, and resolve the described issue in a separate one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request k::api Related to API (application interface) k::design Related to overall design and/or architecture
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants