1use std::array;
6
7use crate::control;
8use crate::device;
9use crate::error::Result;
10use crate::stream::Descriptor as StreamDescriptor;
11use crate::traits::{Context as ContextTrait, Device as DeviceTrait, Stream as StreamTrait};
12
13#[cfg(target_os = "linux")]
14pub(crate) mod v4l2;
15
16#[cfg(any(target_os = "windows", feature = "plat-uvc"))]
17pub(crate) mod uvc;
18
19#[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
20pub(crate) mod openpnp;
21
22pub enum Context<'a> {
29 Custom(Box<dyn 'a + ContextTrait<'a, Device = Device<'a>> + Send>),
31 #[cfg(target_os = "linux")]
32 V4l2(v4l2::context::Context),
34 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
35 Uvc(uvc::context::Context),
37 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
38 OpenPnP(openpnp::context::Context),
40}
41
42impl<'a> Context<'a> {
43 pub fn all() -> impl Iterator<Item = Context<'a>> {
44 array::IntoIter::new([
45 #[cfg(target_os = "linux")]
46 Context::V4l2(v4l2::context::Context {}),
47 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
48 Context::Uvc(uvc::context::Context {}),
49 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
50 Context::OpenPnP(openpnp::context::Context {}),
51 ])
52 }
53}
54
55impl<'a> Default for Context<'a> {
56 fn default() -> Self {
57 Self::all()
58 .next()
59 .expect("no contexts available for this platform")
60 }
61}
62
63impl<'a> ContextTrait<'a> for Context<'a> {
64 type Device = Device<'a>;
65
66 fn devices(&self) -> Result<Vec<device::Description>> {
67 match self {
68 Self::Custom(ctx) => ctx.devices(),
69 #[cfg(target_os = "linux")]
70 Self::V4l2(ctx) => ctx.devices(),
71 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
72 Self::Uvc(ctx) => ctx.devices(),
73 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
74 Self::OpenPnP(ctx) => ctx.devices(),
75 }
76 }
77
78 fn open_device(&self, uri: &str) -> Result<Self::Device> {
79 match self {
80 Self::Custom(ctx) => ctx.open_device(uri),
81 #[cfg(target_os = "linux")]
82 Self::V4l2(ctx) => Ok(Device::V4l2(ctx.open_device(uri)?)),
83 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
84 Self::Uvc(ctx) => Ok(Device::Uvc(ctx.open_device(uri)?)),
85 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
86 Self::OpenPnP(ctx) => Ok(Device::OpenPnP(ctx.open_device(uri)?)),
87 }
88 }
89}
90
91pub enum Device<'a> {
98 Custom(Box<dyn 'a + DeviceTrait<'a, Stream = Stream<'a>> + Send>),
100 #[cfg(target_os = "linux")]
101 V4l2(v4l2::device::Handle),
103 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
104 Uvc(uvc::device::Handle<'a>),
106 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
107 OpenPnP(openpnp::device::Handle),
109}
110
111impl<'a> DeviceTrait<'a> for Device<'a> {
112 type Stream = Stream<'a>;
113
114 fn streams(&self) -> Result<Vec<StreamDescriptor>> {
115 match self {
116 Self::Custom(dev) => dev.streams(),
117 #[cfg(target_os = "linux")]
118 Self::V4l2(dev) => dev.streams(),
119 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
120 Self::Uvc(dev) => dev.streams(),
121 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
122 Self::OpenPnP(dev) => dev.streams(),
123 }
124 }
125
126 fn controls(&self) -> Result<Vec<control::Descriptor>> {
127 match self {
128 Self::Custom(dev) => dev.controls(),
129 #[cfg(target_os = "linux")]
130 Self::V4l2(dev) => dev.controls(),
131 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
132 Self::Uvc(dev) => dev.controls(),
133 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
134 Self::OpenPnP(dev) => dev.controls(),
135 }
136 }
137
138 fn control(&self, id: u32) -> Result<control::State> {
139 match self {
140 Self::Custom(dev) => dev.control(id),
141 #[cfg(target_os = "linux")]
142 Self::V4l2(dev) => dev.control(id),
143 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
144 Self::Uvc(dev) => dev.control(id),
145 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
146 Self::OpenPnP(dev) => dev.control(id),
147 }
148 }
149
150 fn set_control(&mut self, id: u32, val: &control::State) -> Result<()> {
151 match self {
152 Self::Custom(dev) => dev.set_control(id, val),
153 #[cfg(target_os = "linux")]
154 Self::V4l2(dev) => dev.set_control(id, val),
155 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
156 Self::Uvc(dev) => dev.set_control(id, val),
157 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
158 Self::OpenPnP(dev) => dev.set_control(id, val),
159 }
160 }
161
162 fn start_stream(&self, desc: &StreamDescriptor) -> Result<Self::Stream> {
163 match self {
164 Self::Custom(dev) => dev.start_stream(desc),
165 #[cfg(target_os = "linux")]
166 Self::V4l2(dev) => Ok(Stream::V4l2(dev.start_stream(desc)?)),
167 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
168 Self::Uvc(dev) => Ok(Stream::Uvc(dev.start_stream(desc)?)),
169 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
170 Self::OpenPnP(dev) => Ok(Stream::OpenPnP(dev.start_stream(desc)?)),
171 }
172 }
173}
174
175pub enum Stream<'a> {
184 Custom(Box<dyn 'a + for<'b> StreamTrait<'b, Item = Result<&'b [u8]>> + Send>),
186 #[cfg(target_os = "linux")]
187 V4l2(v4l2::stream::Handle<'a>),
189 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
190 Uvc(uvc::stream::Handle<'a>),
192 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
193 OpenPnP(openpnp::stream::Handle),
195}
196
197impl<'a, 'b> StreamTrait<'b> for Stream<'a> {
198 type Item = Result<&'b [u8]>;
199
200 fn next(&'b mut self) -> Option<Self::Item> {
201 match self {
202 Self::Custom(stream) => stream.next(),
203 #[cfg(target_os = "linux")]
204 Self::V4l2(stream) => stream.next(),
205 #[cfg(any(target_os = "windows", feature = "plat-uvc"))]
206 Self::Uvc(stream) => stream.next(),
207 #[cfg(any(target_os = "macos", feature = "plat-openpnp"))]
208 Self::OpenPnP(stream) => stream.next(),
209 }
210 }
211}