ndi-sdk-sys 0.1.2

Rust bindings for the NDI SDK
Documentation
use std::{
    ffi::{CStr, CString},
    sync::Arc,
};

pub(crate) use crate::bindings::NDIlib_metadata_frame_t as NDIRawMetadataFrame;
use crate::{bindings, receiver::RawReceiver, sender::RawSender};

use super::{NDIFrame, RawBufferManagement, RawFrame, drop_guard::FrameDataDropGuard};

impl RawBufferManagement for NDIRawMetadataFrame {
    #[inline]
    unsafe fn drop_with_recv(&mut self, recv: &Arc<RawReceiver>) {
        unsafe { bindings::NDIlib_recv_free_metadata(recv.raw_ptr(), self) }
    }

    #[inline]
    unsafe fn drop_with_sender(&mut self, sender: &Arc<RawSender>) {
        unsafe { bindings::NDIlib_send_free_metadata(sender.raw_ptr(), self) }
    }

    fn assert_unwritten(&self) {
        assert!(
            self.p_data.is_null(),
            "[Fatal FFI Error] NDIRawMetadataFrame data is not null, but should be."
        );
    }
}

unsafe impl Send for NDIRawMetadataFrame {}
unsafe impl Sync for NDIRawMetadataFrame {}

impl RawFrame for NDIRawMetadataFrame {}

pub type MetadataFrame = NDIFrame<NDIRawMetadataFrame>;

impl MetadataFrame {
    pub fn new() -> Self {
        let raw = NDIRawMetadataFrame {
            timecode: bindings::NDIlib_send_timecode_synthesize,
            p_data: std::ptr::null_mut(),
            length: 0,
        };
        Self {
            raw,
            alloc: FrameDataDropGuard::NullPtr,
            custom_state: (),
        }
    }

    pub fn from_string(cstr: CString) -> Self {
        let raw = NDIRawMetadataFrame {
            timecode: bindings::NDIlib_send_timecode_synthesize,
            p_data: cstr.as_ptr() as *mut _,
            length: cstr.as_bytes_with_nul().len() as i32,
        };
        Self {
            raw,
            alloc: FrameDataDropGuard::CString(cstr),
            custom_state: (),
        }
    }

    pub fn to_str(&self) -> Option<&CStr> {
        if let FrameDataDropGuard::CString(cstr) = &self.alloc {
            return Some(cstr.as_c_str());
        }
        if self.raw.p_data.is_null() {
            None
        } else {
            let str = unsafe { CStr::from_ptr(self.raw.p_data as *const _) };
            if self.raw.length > 0 {
                assert_eq!(
                    str.to_bytes_with_nul().len(),
                    self.raw.length as usize,
                    "[Fatal FFI Error] NDIFrame::to_cstr: length mismatch"
                );
            }
            Some(str)
        }
    }

    // TODO: implement editing of metadata frames, otherwise this doesn't make much sense
    // pub fn dealloc(&mut self) {
    //     unsafe { self.alloc.drop_buffer(&mut self.raw) };
    //     self.raw.p_data = std::ptr::null_mut();
    //     self.raw.length = 0;
    // }
}

impl From<CString> for MetadataFrame {
    fn from(cstr: CString) -> Self {
        Self::from_string(cstr)
    }
}