SEDSnet 4.3.7

A memory safe, no_std-capable networking stack with routing, discovery, reliability, and Rust/C/Python bindings.
Documentation
use super::*;
use core::sync::atomic::{AtomicUsize, Ordering};

fn schema(name: &str) -> (DataType, DataEndpoint) {
    let ep = crate::config::register_endpoint(name, false).unwrap();
    let ty = crate::config::register_data_type(
        name,
        MessageElement::Static(1, crate::MessageDataType::UInt8, crate::MessageClass::Data),
        &[ep],
        crate::ReliableMode::None,
        0,
    )
    .unwrap();
    (ty, ep)
}

#[test]
fn c_cache_retirement_validates_handles_and_optional_outputs() {
    let (ty, ep) = schema("C_CACHE_RETIREMENT");
    let bad = status_from_err(TelemetryError::BadArg);
    let mut removed = true;
    let mut count = 77;
    assert_eq!(
        seds_router_invalidate_network_variable_cache(ptr::null_mut(), ty, &mut removed),
        bad
    );
    assert_eq!(
        seds_router_clear_network_variable_caches(ptr::null_mut(), &mut count),
        bad
    );
    assert!(removed);
    assert_eq!(count, 77);
    let mut handle = SedsRouter {
        inner: Arc::new(Router::new(RouterConfig::new([]))),
    };
    assert_eq!(
        seds_router_enable_network_variable(&mut handle, ty, true, false),
        0
    );
    let value = Packet::new(ty, &[ep], "CACHE_WRITER", 41, Arc::from([1])).unwrap();
    let wire = pack_packet(&value);
    assert_eq!(
        seds_router_seed_managed_variable_packed(&mut handle, wire.as_ptr(), wire.len()),
        0
    );
    assert_eq!(
        seds_router_invalidate_network_variable_cache(&mut handle, ty, &mut removed),
        0
    );
    assert!(removed);
    assert_eq!(
        seds_router_cached_managed_variable_packed_len(&mut handle, ty),
        0
    );
    assert_eq!(
        seds_router_invalidate_network_variable_cache(&mut handle, ty, ptr::null_mut()),
        0
    );
    assert_eq!(
        seds_router_seed_managed_variable_packed(&mut handle, wire.as_ptr(), wire.len()),
        0
    );
    assert_eq!(
        seds_router_clear_network_variable_caches(&mut handle, &mut count),
        0
    );
    assert_eq!(count, 1);
    assert_eq!(
        seds_router_clear_network_variable_caches(&mut handle, ptr::null_mut()),
        0
    );
    assert_eq!(
        seds_router_set_network_variable_packed(&mut handle, wire.as_ptr(), wire.len()),
        status_from_err(TelemetryError::PermissionDenied)
    );
    let mut relay = SedsRouter {
        inner: Arc::new(Router::new(RouterConfig::relay())),
    };
    assert_eq!(
        seds_router_invalidate_network_variable_cache(&mut relay, ty, &mut removed),
        0
    );
    assert!(!removed);
    assert_eq!(
        seds_router_clear_network_variable_caches(&mut relay, &mut count),
        0
    );
    assert_eq!(count, 0);
    assert!(matches!(
        relay.inner.tx(value),
        Err(TelemetryError::PermissionDenied)
    ));
}

struct RetryState {
    router: *mut SedsRouter,
    ty: DataType,
    calls: AtomicUsize,
    retire: bool,
}
extern "C" fn reject_first(_packet: *const SedsPacketView, user: *mut c_void) -> i32 {
    let state = unsafe { &*(user as *const RetryState) };
    if state.calls.fetch_add(1, Ordering::Relaxed) == 0 {
        if state.retire {
            let mut removed = false;
            assert_eq!(
                seds_router_invalidate_network_variable_cache(state.router, state.ty, &mut removed),
                0
            );
            assert!(removed);
        }
        return status_from_err(TelemetryError::HandlerError("injected owner refusal"));
    }
    0
}

#[test]
fn c_callback_can_retire_rejected_packet_and_keep_exact_wire_retry() {
    for retire in [false, true] {
        let (ty, ep) = schema(if retire {
            "C_CACHE_RETRY_RETIRE"
        } else {
            "C_CACHE_RETRY_CONTROL"
        });
        let mut handle = SedsRouter {
            inner: Arc::new(Router::new(RouterConfig::new([
                EndpointHandler::new_packet_handler(ep, |_| Ok(())),
            ]))),
        };
        let mut state = RetryState {
            router: &mut handle,
            ty,
            calls: AtomicUsize::new(0),
            retire,
        };
        assert_eq!(
            seds_router_enable_network_variable(&mut handle, ty, true, false),
            0
        );
        assert_eq!(
            seds_router_on_network_variable_update(
                &mut handle,
                ty,
                Some(reject_first),
                (&mut state as *mut RetryState).cast()
            ),
            0
        );
        let side = handle.inner.add_side_packed("source", |_| Ok(()));
        let packet = Packet::new(ty, &[ep], "CACHE_WRITER", 42, Arc::from([2])).unwrap();
        let bytes = pack_packet(&packet);
        assert_ne!(
            seds_router_receive_packed_from_side(
                &mut handle,
                side as u32,
                bytes.as_ptr(),
                bytes.len()
            ),
            0
        );
        assert_eq!(state.calls.load(Ordering::Relaxed), 1);
        assert_eq!(handle.inner.cached_managed_variable(ty).is_none(), retire);
        assert_eq!(
            seds_router_receive_packed_from_side(
                &mut handle,
                side as u32,
                bytes.as_ptr(),
                bytes.len()
            ),
            0
        );
        assert_eq!(
            state.calls.load(Ordering::Relaxed),
            if retire { 2 } else { 1 },
            "negative control keeps the original poisoned-cache behavior; explicit retirement must allow its exact retry"
        );
    }
}