Skip to content

2.1.0

Latest

Choose a tag to compare

@LK-Simon LK-Simon released this 11 Aug 11:39
· 4 commits to main since this release

Full Changelog: 1.0.0...2.1.0

ESPressio Observable 2.0 integration

Dependency changes

  • Added Flowduino ESPressio-Observable version 2.0.0 to library.json.
  • Added Flowduino ESPressio-Observable (>=2.0.0) to library.properties.
  • Retained ESPressio Threads as the asynchronous Event-processing dependency.
  • Updated the README dependency and PlatformIO examples to include ESPressio Observable 2.0.0.

Typed Event Observer API

  • Added ESPressio_EventObserver.hpp.
  • Added the typed IEventObserver<EventType> interface.
  • Made IEventObserver<EventType> derive from ESPressio Observable's IObserver.
  • Used virtual IObserver inheritance so one object can implement multiple IEventObserver<EventType> interfaces without creating ambiguous IObserver base objects.
  • Added the required typed Observer method:
virtual void OnEvent(
    EventType* event,
    EventDispatchMethod dispatchMethod,
    EventPriority priority
) = 0;
  • Added the optional custom-interest method:
virtual bool IsInterestedInEvent(EventType* event);
  • The default IsInterestedInEvent() implementation returns true.

Observer registration

  • Added RegisterObserver<EventType>() to IEventListener.
  • Made Observer registration available through both EventListener and EventThread.
  • Adapted typed Observer methods into the existing asynchronous Event listener pipeline.
  • Preserved the existing RegisterListener() callback API.
  • Allowed callback listeners and typed Observers to coexist for the same Event type.
  • Passed identical Event, dispatch-method, and priority values to callbacks and Observers.
  • Preserved the existing caller-owned IEventListenerHandle lifetime model.
  • Added typed null-Observer rejection using InvalidObserverRegistrationException.

Observer interest filtering

  • Added support for EventListenerInterest::All.
  • Added support for EventListenerInterest::YoungerThan.
  • Added support for EventListenerInterest::Custom.
  • Custom Observer filtering invokes IsInterestedInEvent() instead of requiring a predicate callback.
  • Preserved independent interest policies for every Observer registration.
  • Allowed one Observer object to register independently for multiple Event types.

Public header integration

  • Added ESPressio_EventObserver.hpp to the main ESPressio_Event.hpp include surface.
  • Added the Observable exception and Observer interfaces to EventListener's required includes.
  • Added missing direct standard-library includes used by EventListener.

Listener dispatch safety

  • Replaced unsafe casts between different EventListenerContainer<EventType> template specializations.
  • Added a virtual, type-erased ProcessEvent() operation to the listener-container interface.
  • Each typed listener container now performs a checked dynamic_cast to its actual Event type.
  • Event callbacks are invoked only when the Event matches the container's declared Event type.
  • Centralized All, YoungerThan, and Custom interest evaluation inside each typed listener container.
  • Custom-interest registrations with no predicate are now treated as uninterested instead of invoking an empty function.

Callback and Observer exception safety

  • Added an event-reference RAII guard to ProcessEvent().
  • Event references are now released when callbacks or Observer methods throw.
  • Replaced manual shared-mutex locking with RAII locks.
  • Listener registry locks are now released automatically during exceptions.
  • Callback and Observer exceptions continue to propagate to the caller after cleanup.

Callback-time registration and unregistration

  • Changed listener buckets to store shared listener-container records.
  • ProcessEvent() now copies a stable listener snapshot while holding the registry lock.
  • The registry lock is released before callbacks or Observer methods execute.
  • Callback listeners can now unregister themselves safely.
  • Typed Event Observers can now unregister themselves safely.
  • Other listeners can be registered or unregistered during Event processing without invalidating the active dispatch snapshot.
  • Removed the previous callback-time deadlock and use-after-free risk.

EventManager routing fixes

  • EventManager routing is now registered only when the first listener or Observer for an Event type is added.
  • Removing one registration no longer disables routing while other callbacks or Observers for the same Event type remain.
  • EventManager routing is unregistered only after the final registration for that Event type is removed.
  • Empty listener buckets are now deleted instead of being leaked.
  • Added an explicit UnregisterAllListeners() shutdown path.
  • EventThread now unregisters all Event types before its listener base is destroyed.
  • Added the previously missing EventManager registration and unregistration hooks to EventThreadWithLoop.
  • EventThreadWithLoop now unregisters all Event types during destruction.
  • Prevented EventManager from retaining dangling EventThread receiver pointers after destruction.

Event Listener Handle improvements

  • Replaced the heap-allocated registration-state mutex with a directly owned ReadWriteMutex<bool>.
  • Removed the registration-state allocation leak.
  • Added explicit override declarations to handle interface implementations.
  • Handles are forcibly invalidated when their owning EventListener is destroyed.
  • A handle that outlives its EventListener now reports itself as unregistered.
  • Repeated handle unregistration remains safe and idempotent.

Registration exception safety

  • Replaced manual registry locking with std::unique_lock.
  • Used temporary smart pointers while constructing listener handles and containers.
  • Listener handles and containers are released to caller/registry ownership only after insertion succeeds.
  • Failed allocations or container insertions now release partially constructed state automatically.
  • EventManager registration hooks run only after registry locks have been released.

Documentation

  • Documented the ESPressio Observable 2.0.0 dependency.
  • Added a complete typed Event Observer example.
  • Documented Observer and callback coexistence.
  • Documented non-owning Observer lifetime requirements.
  • Documented caller ownership of returned IEventListenerHandle objects.
  • Documented all supported interest modes.
  • Added a custom IsInterestedInEvent() example.
  • Documented multi-Event Observer implementations and independent registrations.

Tests

  • Added a repository-owned CMake/CTest integration suite.
  • Added a host-side ESPressio Threads test stub.
  • Verified that IEventObserver<EventType> satisfies ESPressio Observable's IObserver interface.
  • Verified that multi-Event Observers have one unambiguous IObserver identity.
  • Verified null Observer rejection and exact exception typing.
  • Verified normal Observer delivery.
  • Verified callback and Observer coexistence.
  • Verified Event pointer, dispatch-method, and priority forwarding.
  • Verified All interest behavior.
  • Verified YoungerThan boundary behavior.
  • Verified custom-interest acceptance and rejection.
  • Verified multi-Event Observer delivery.
  • Verified handle-driven unregistration.
  • Verified repeated unregistration.
  • Verified Observer self-unregistration during Event processing.
  • Verified callback exception propagation.
  • Verified event-reference cleanup following callback exceptions.
  • Verified Event processing when no listener bucket exists.
  • Verified routing registration occurs only for the first listener.
  • Verified routing remains active when one of several registrations is removed.
  • Verified routing unregistration occurs after the final listener is removed.
  • Verified handle invalidation when an EventListener is destroyed.
  • Verified explicit all-listener shutdown behavior.

Verification

  • Passed strict C++17 compilation with:
    • -Wall
    • -Wextra
    • -Wpedantic
    • -Werror
  • Passed AddressSanitizer.
  • Passed UndefinedBehaviorSanitizer.
  • Passed standalone ESPressio_EventObserver.hpp compilation.
  • Passed standalone ESPressio_EventListener.hpp compilation.
  • Passed library.json validation.
  • Passed git diff --check.