Skip to content

File syn_pubsub.c

File List > src > syntropic > util > syn_pubsub.c

Go to the documentation of this file

#if __has_include("syn_config.h")
#include "syn_config.h"
#endif

#if !defined(SYN_USE_PUBSUB) || SYN_USE_PUBSUB

#include "syn_assert.h"
#include "syn_pubsub.h"

void syn_pubsub_init(SYN_PubSubBroker *broker, SYN_PubSubSub *sub_array, size_t capacity)
{
    SYN_ASSERT(broker != NULL);
    SYN_ASSERT(sub_array != NULL || capacity == 0);

    if (broker == NULL) {
        return;
    }

    broker->subs = sub_array;
    broker->capacity = capacity;
    broker->count = 0;
}

bool syn_pubsub_subscribe(SYN_PubSubBroker *broker, uint16_t topic, SYN_PubSubHandler handler,
                          void *ctx)
{
    SYN_ASSERT(broker != NULL);
    SYN_ASSERT(handler != NULL);

    if (broker == NULL || broker->subs == NULL || handler == NULL) {
        return false;
    }

    if (broker->count >= broker->capacity) {
        return false;
    }

    // Avoid exact duplicates
    for (size_t i = 0; i < broker->count; i++) {
        if (broker->subs[i].topic == topic && broker->subs[i].handler == handler &&
            broker->subs[i].ctx == ctx) {
            return true; // Already subscribed
        }
    }

    broker->subs[broker->count].topic = topic;
    broker->subs[broker->count].handler = handler;
    broker->subs[broker->count].ctx = ctx;
    broker->count++;
    return true;
}

bool syn_pubsub_unsubscribe(SYN_PubSubBroker *broker, uint16_t topic, SYN_PubSubHandler handler)
{
    SYN_ASSERT(broker != NULL);
    SYN_ASSERT(handler != NULL);

    if (broker == NULL || broker->subs == NULL || handler == NULL) {
        return false;
    }

    for (size_t i = 0; i < broker->count; i++) {
        if (broker->subs[i].topic == topic && broker->subs[i].handler == handler) {
            // Swap with last element to remove (O(1) removal, unordered)
            broker->count--;
            if (i != broker->count) {
                broker->subs[i] = broker->subs[broker->count];
            }
            return true;
        }
    }
    return false;
}

void syn_pubsub_publish(SYN_PubSubBroker *broker, uint16_t topic, const void *payload, size_t len)
{
    if (broker == NULL || broker->subs == NULL) {
        return;
    }
    SYN_ASSERT(broker != NULL);

    size_t count = broker->count;
    for (size_t i = 0; i < count && i < broker->count; i++) {
        if (broker->subs[i].handler != NULL &&
            (broker->subs[i].topic == topic || broker->subs[i].topic == SYN_PUBSUB_TOPIC_ALL)) {
            broker->subs[i].handler(topic, payload, len, broker->subs[i].ctx);
        }
    }
}

#endif /* SYN_USE_PUBSUB */