skip to content
==> src/place_compose.c <==
1/* place.rs: read_state, write_state, gather, scatter, sys_nibbles, Composer. */
2#include "mesh/place_compose.h"
3#include "mesh/rust_fmt.h"
4#include "mesh/mt.h"
5
6#include <stdlib.h>
7#include <string.h>
8
9mpw_bytes mpc_read_state(const mps_spec *s, mpc_read_fn read, void *ctx) {
10    mpw_bytes o = {0};
11    for (size_t i = 0; i < s->nstate; i++) {
12        uint8_t *b = mt_alloc(s->state[i].len ? s->state[i].len : 1);
13        read(ctx, s->state[i].off, s->state[i].len, b);
14        mpw_put(&o, b, s->state[i].len);
15        free(b);
16    }
17    return o;
18}
19
20bool mpc_write_state(const mps_spec *s, const uint8_t *b, size_t n, mpc_write_fn write, void *ctx, char **err) {
21    if (n != mps_state_bytes(s)) {
22        *err = mt_fmt("state of %zu bytes, the manifest declares %zu", n, mps_state_bytes(s));
23        return false;
24    }
25    size_t at = 0;
26    for (size_t i = 0; i < s->nstate; i++) {
27        write(ctx, s->state[i].off, b + at, s->state[i].len);
28        at += s->state[i].len;
29    }
30    return true;
31}
32
33mpw_bytes mpc_gather(const mps_spec *s, uint32_t mask, mpc_read_fn read, void *ctx) {
34    mpw_bytes o = {0};
35    mps_region *r = mt_alloc((s->nout ? s->nout : 1) * sizeof *r);
36    for (uint32_t b = 0; b < s->fanout; b++) {
37        if (!(mask >> b & 1)) continue;
38        mps_part(s, b, r);
39        for (size_t i = 0; i < s->nout; i++) {
40            uint8_t *x = mt_alloc(r[i].len ? r[i].len : 1);
41            read(ctx, r[i].off, r[i].len, x);
42            mpw_put(&o, x, r[i].len);
43            free(x);
44        }
45    }
46    free(r);
47    return o;
48}
49
50static int popcount(uint32_t x) {
51    int n = 0;
52    for (; x; x &= x - 1) n++;
53    return n;
54}
55
56bool mpc_scatter(const mps_spec *s, uint8_t *buf, size_t nbuf, uint32_t mask, const uint8_t *data, size_t ndata, char **err) {
57    size_t want = (size_t)popcount(mask) * mps_part_bytes(s);
58    if (ndata != want || nbuf != mps_out_bytes(s)) {
59        char h[24];
60        *err = mt_fmt("frame data of %zu bytes, parts %s need %zu", ndata, rf_hex_alt(h, mask), want);
61        return false;
62    }
63    mps_region *r = mt_alloc((s->nout ? s->nout : 1) * sizeof *r);
64    size_t at = 0;
65    for (uint32_t b = 0; b < s->fanout; b++) {
66        if (!(mask >> b & 1)) continue;
67        mps_part_in_buffer(s, b, r);
68        for (size_t i = 0; i < s->nout; i++) {
69            memcpy(buf + r[i].off, data + at, r[i].len);
70            at += r[i].len;
71        }
72    }
73    free(r);
74    return true;
75}
76
77uint32_t mpc_sys_nibbles(uint32_t mask, uint32_t sys) {
78    uint32_t w = 0;
79    for (uint32_t b = 0; b < 8; b++)
80        if (mask >> b & 1) w |= (sys & 15) << (4 * b);
81    return w;
82}
83
84static void pending_free(mpc_pending *p) {
85    free(p->buf);
86    p->buf = NULL;
87}
88
89static void remove_at(mpc_composer *c, size_t i, bool free_buf) {
90    if (free_buf) pending_free(&c->q[i]);
91    memmove(c->q + i, c->q + i + 1, (c->n - i - 1) * sizeof *c->q);
92    c->n--;
93}
94
95int mpc_add(mpc_composer *c, const mps_spec *s, uint32_t frame, uint32_t parts, uint32_t sys, const uint8_t *data, size_t n, uint64_t now, mpc_whole *whole,
96            char **err) {
97    size_t i = 0;
98    for (; i < c->n; i++)
99        if (c->q[i].frame == frame) break;
100    if (i == c->n) {
101        if (c->n >= MPC_PENDING) remove_at(c, 0, true);
102        c->q[c->n++] = (mpc_pending){frame, 0, 0, mt_alloc(mps_out_bytes(s) ? mps_out_bytes(s) : 1), now};
103        i = c->n - 1;
104    }
105    mpc_pending *p = &c->q[i];
106    if (p->have & parts) {
107        char h[24];
108        *err = mt_fmt("frame %u: parts %s arrived twice", frame, rf_hex_alt(h, parts));
109        return -1;
110    }
111    if (!mpc_scatter(s, p->buf, mps_out_bytes(s), parts, data, n, err)) return -1;
112    p->have |= parts;
113    p->sys |= mpc_sys_nibbles(parts, sys);
114    uint32_t all = s->fanout >= 32 ? UINT32_MAX : (1u << s->fanout) - 1;
115    if (p->have != all) return 0;
116    *whole = (mpc_whole){p->frame, p->sys, p->buf, mps_out_bytes(s), p->t0};
117    remove_at(c, i, false);
118    /* Older frames can no longer be shown (a newer one is): drop them. */
119    for (size_t j = c->n; j-- > 0;)
120        if (!((int32_t)(c->q[j].frame - frame) > 0)) remove_at(c, j, true);
121    return 1;
122}
123
124void mpc_clear(mpc_composer *c) {
125    for (size_t i = 0; i < c->n; i++) pending_free(&c->q[i]);
126    c->n = 0;
127}