1use std::{
7 ffi::{CStr, CString},
8 fmt::Debug,
9 marker::PhantomData,
10 ptr,
11};
12
13use static_assertions::assert_impl_all;
14
15use crate::{
16 bindings,
17 util::{SourceNameError, validate_source_name},
18};
19
20pub unsafe trait NDISourceLike: Debug {
26 fn with_descriptor<R>(&self, f: impl FnOnce(*const bindings::NDIlib_source_t) -> R) -> R;
34}
35
36#[derive(Debug, Clone, Copy)]
38pub(crate) struct NullPtrSource;
39
40unsafe impl NDISourceLike for NullPtrSource {
41 fn with_descriptor<R>(&self, f: impl FnOnce(*const bindings::NDIlib_source_t) -> R) -> R {
45 f(ptr::null())
46 }
47}
48
49unsafe impl<S: NDISourceLike> NDISourceLike for Option<S> {
50 fn with_descriptor<R>(&self, f: impl FnOnce(*const bindings::NDIlib_source_t) -> R) -> R {
51 if let Some(source) = self {
52 source.with_descriptor(f)
53 } else {
54 NullPtrSource.with_descriptor(f)
55 }
56 }
57}
58
59#[derive(Clone)]
66pub struct NDISourceRef<'a> {
67 name: &'a CStr,
69 raw: bindings::NDIlib_source_t,
70 raw_ptrs: PhantomData<&'a CStr>,
71}
72impl<'a> NDISourceRef<'a> {
76 pub(crate) unsafe fn from(source_t: bindings::NDIlib_source_t) -> Self {
77 if source_t.p_ndi_name.is_null() {
78 panic!("[Fatal FFI Error] NDI SDK returned nullptr for source name")
79 } else {
80 let name = unsafe { CStr::from_ptr(source_t.p_ndi_name) };
81 NDISourceRef {
82 name,
83 raw: source_t,
84 raw_ptrs: PhantomData,
85 }
86 }
87 }
88
89 pub fn name(&'a self) -> &'a CStr {
91 self.name
92 }
93
94 pub fn to_owned(&self) -> NDISource {
96 let descriptor_anon_1 = self.raw.__bindgen_anon_1;
97 let descriptor_anon_1: *const ::std::os::raw::c_char =
98 unsafe { descriptor_anon_1.p_url_address };
99 let descriptor_anon_1 = if descriptor_anon_1.is_null() {
100 None
101 } else {
102 Some(unsafe { CStr::from_ptr(descriptor_anon_1).to_owned() })
103 };
104
105 let name = self.name.to_owned();
106
107 NDISource {
108 name: name.clone().into_string().unwrap(),
109 name_c: name,
110 descriptor_anon_1,
111 }
112 }
113}
114
115unsafe impl NDISourceLike for &NDISourceRef<'_> {
116 fn with_descriptor<R>(&self, f: impl FnOnce(*const bindings::NDIlib_source_t) -> R) -> R {
117 f(&self.raw)
118 }
119}
120
121impl std::fmt::Debug for NDISourceRef<'_> {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 let descriptor_anon_1 = self.raw.__bindgen_anon_1;
124 let descriptor_anon_1: *const ::std::os::raw::c_char =
125 unsafe { descriptor_anon_1.p_url_address };
126
127 let mut dbg = f.debug_struct("NDISourceRef");
128
129 dbg.field("name", &self.name.to_str());
130
131 if !descriptor_anon_1.is_null() {
132 let descriptor = unsafe { CStr::from_ptr(descriptor_anon_1) };
133 dbg.field("raw_src", &descriptor);
134 } else {
135 dbg.field("raw_src", &"null");
136 }
137
138 dbg.finish()
139 }
140}
141
142#[derive(Clone, Hash, PartialEq, Eq)]
147pub struct NDISource {
148 name: String,
149 name_c: CString,
150 descriptor_anon_1: Option<CString>,
151}
152
153assert_impl_all!(NDISource: Send, Sync);
154
155impl NDISource {
156 pub fn from_name(name: &str) -> Result<Self, SourceNameError> {
157 let name_c = validate_source_name(name)?;
158 Ok(NDISource {
159 name: name.to_owned(),
160 name_c,
161 descriptor_anon_1: None,
162 })
163 }
164
165 pub fn name(&self) -> &str {
166 self.name.as_str()
167 }
168
169 pub fn name_c_str(&self) -> &CStr {
170 &self.name_c
171 }
172}
173
174unsafe impl NDISourceLike for NDISource {
175 fn with_descriptor<R>(&self, f: impl FnOnce(*const bindings::NDIlib_source_t) -> R) -> R {
176 let descriptor = bindings::NDIlib_source_t {
177 p_ndi_name: self.name_c.as_ptr(),
178 __bindgen_anon_1: bindings::NDIlib_source_t__bindgen_ty_1 {
179 p_url_address: self
180 .descriptor_anon_1
181 .as_ref()
182 .map(|s| s.as_ptr())
183 .unwrap_or(ptr::null()),
184 },
185 };
186 f(&descriptor)
187 }
188}
189
190unsafe impl NDISourceLike for &NDISource {
191 fn with_descriptor<R>(&self, f: impl FnOnce(*const bindings::NDIlib_source_t) -> R) -> R {
192 (*self).with_descriptor(f)
193 }
194}
195
196impl std::fmt::Debug for NDISource {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 f.debug_struct("NDISource")
199 .field("name", &self.name)
200 .field("raw_src", &self.descriptor_anon_1)
201 .finish()
202 }
203}