1use serde::Serialize;
2use std::io::{Seek, Write};
3
4#[cfg(unix)]
5use std::os::fd::OwnedFd;
6
7#[cfg(feature = "gvariant")]
8#[allow(deprecated)]
9use crate::gvariant::Serializer as GVSerializer;
10use crate::{
11 Basic, DynamicType, Error, Result, Signature,
12 container_depths::ContainerDepths,
13 dbus::Serializer as DBusSerializer,
14 serialized::{Context, Data, Format, Size, Written},
15 utils::*,
16};
17
18struct NullWriteSeek;
19
20impl Write for NullWriteSeek {
21 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
22 Ok(buf.len())
23 }
24
25 fn flush(&mut self) -> std::io::Result<()> {
26 Ok(())
27 }
28}
29
30impl Seek for NullWriteSeek {
31 fn seek(&mut self, _pos: std::io::SeekFrom) -> std::io::Result<u64> {
32 Ok(u64::MAX) }
34}
35
36pub fn serialized_size<T>(ctxt: Context, value: &T) -> Result<Size>
51where
52 T: ?Sized + Serialize + DynamicType,
53{
54 let mut null = NullWriteSeek;
55 let signature = value.signature();
56 #[cfg(unix)]
57 let mut fds = FdList::Number(0);
58
59 let len = match ctxt.format() {
60 Format::DBus => {
61 let mut ser = DBusSerializer::<NullWriteSeek>::new(
62 &signature,
63 &mut null,
64 #[cfg(unix)]
65 &mut fds,
66 ctxt,
67 )?;
68 value.serialize(&mut ser)?;
69 ser.0.bytes_written
70 }
71 #[cfg(feature = "gvariant")]
72 #[allow(deprecated)]
73 Format::GVariant => {
74 let mut ser = GVSerializer::<NullWriteSeek>::new(
75 &signature,
76 &mut null,
77 #[cfg(unix)]
78 &mut fds,
79 ctxt,
80 )?;
81 value.serialize(&mut ser)?;
82 ser.0.bytes_written
83 }
84 #[cfg(not(feature = "gvariant"))]
93 #[allow(unreachable_patterns)]
94 _ => {
95 return Err(Error::Message(
96 "GVariant support has moved to the `zgvariant` crate; enable `zvariant`'s \
97 deprecated `gvariant` feature only for legacy compatibility"
98 .to_owned(),
99 ));
100 }
101 };
102
103 let size = Size::new(len, ctxt);
104 #[cfg(unix)]
105 let size = match fds {
106 FdList::Number(n) => size.set_num_fds(n),
107 FdList::Fds(_) => unreachable!("`Fds::Fds` is not possible here"),
108 };
109
110 Ok(size)
111}
112
113pub unsafe fn to_writer<W, T>(writer: &mut W, ctxt: Context, value: &T) -> Result<Written>
139where
140 W: Write + Seek,
141 T: ?Sized + Serialize + DynamicType,
142{
143 unsafe {
144 let signature = value.signature();
145
146 to_writer_for_signature(writer, ctxt, signature, value)
147 }
148}
149
150pub fn to_bytes<T>(ctxt: Context, value: &T) -> Result<Data<'static, 'static>>
154where
155 T: ?Sized + Serialize + DynamicType,
156{
157 to_bytes_for_signature(ctxt, value.signature(), value)
158}
159
160pub unsafe fn to_writer_for_signature<W, S, T>(
177 writer: &mut W,
178 ctxt: Context,
179 signature: S,
180 value: &T,
181) -> Result<Written>
182where
183 W: Write + Seek,
184 S: TryInto<Signature>,
185 S::Error: Into<Error>,
186 T: ?Sized + Serialize,
187{
188 let signature = signature.try_into().map_err(Into::into)?;
189
190 #[cfg(unix)]
191 let mut fds = FdList::Fds(vec![]);
192
193 let len = match ctxt.format() {
194 Format::DBus => {
195 let mut ser = DBusSerializer::<W>::new(
196 &signature,
197 writer,
198 #[cfg(unix)]
199 &mut fds,
200 ctxt,
201 )?;
202 value.serialize(&mut ser)?;
203 ser.0.bytes_written
204 }
205 #[cfg(feature = "gvariant")]
206 #[allow(deprecated)]
207 Format::GVariant => {
208 let mut ser = GVSerializer::<W>::new(
209 &signature,
210 writer,
211 #[cfg(unix)]
212 &mut fds,
213 ctxt,
214 )?;
215 value.serialize(&mut ser)?;
216 ser.0.bytes_written
217 }
218 #[cfg(not(feature = "gvariant"))]
220 #[allow(unreachable_patterns)]
221 _ => {
222 return Err(Error::Message(
223 "GVariant support has moved to the `zgvariant` crate; enable `zvariant`'s \
224 deprecated `gvariant` feature only for legacy compatibility"
225 .to_owned(),
226 ));
227 }
228 };
229
230 let written = Written::new(len, ctxt);
231 #[cfg(unix)]
232 let written = match fds {
233 FdList::Fds(fds) => written.set_fds(fds),
234 FdList::Number(_) => unreachable!("`Fds::Number` is not possible here"),
235 };
236
237 Ok(written)
238}
239
240pub fn to_bytes_for_signature<S, T>(
246 ctxt: Context,
247 signature: S,
248 value: &T,
249) -> Result<Data<'static, 'static>>
250where
251 S: TryInto<Signature>,
252 S::Error: Into<Error>,
253 T: ?Sized + Serialize,
254{
255 let mut cursor = std::io::Cursor::new(vec![]);
256 let ret = unsafe { to_writer_for_signature(&mut cursor, ctxt, signature, value) }?;
259 #[cfg(unix)]
260 let encoded = Data::new_fds(cursor.into_inner(), ctxt, ret.into_fds());
261 #[cfg(not(unix))]
262 let encoded = {
263 let _ = ret;
264 Data::new(cursor.into_inner(), ctxt)
265 };
266
267 Ok(encoded)
268}
269
270pub(crate) struct SerializerCommon<'ser, W> {
272 pub(crate) ctxt: Context,
273 pub(crate) writer: &'ser mut W,
274 pub(crate) bytes_written: usize,
275 #[cfg(unix)]
276 pub(crate) fds: &'ser mut FdList,
277
278 pub(crate) signature: &'ser Signature,
279
280 pub(crate) value_sign: Option<Signature>,
281
282 pub(crate) container_depths: ContainerDepths,
283}
284
285#[cfg(unix)]
286pub(crate) enum FdList {
287 Fds(Vec<OwnedFd>),
288 Number(u32),
289}
290
291impl<W> SerializerCommon<'_, W>
292where
293 W: Write + Seek,
294{
295 #[cfg(unix)]
296 pub(crate) fn add_fd(&mut self, fd: std::os::fd::RawFd) -> Result<u32> {
297 use std::os::fd::{AsRawFd, BorrowedFd};
298
299 match self.fds {
300 FdList::Fds(fds) => {
301 if let Some(idx) = fds.iter().position(|x| x.as_raw_fd() == fd) {
302 return Ok(idx as u32);
303 }
304 let idx = fds.len();
305 let fd = unsafe { BorrowedFd::borrow_raw(fd) }.try_clone_to_owned()?;
308 fds.push(fd);
309
310 Ok(idx as u32)
311 }
312 FdList::Number(n) => {
313 let idx = *n;
314 *n += 1;
315
316 Ok(idx)
317 }
318 }
319 }
320
321 pub(crate) fn add_padding(&mut self, alignment: usize) -> Result<usize> {
322 let padding = padding_for_n_bytes(self.abs_pos(), alignment);
323 if padding > 0 {
324 self.write_all(&[0u8; 8][..padding])?;
325 }
326
327 Ok(padding)
328 }
329
330 pub(crate) fn prep_serialize_basic<T>(&mut self) -> Result<()>
331 where
332 T: Basic,
333 {
334 self.add_padding(T::alignment(self.ctxt.format()))?;
335
336 Ok(())
337 }
338
339 fn abs_pos(&self) -> usize {
340 self.ctxt.position() + self.bytes_written
341 }
342}
343
344impl<W> Write for SerializerCommon<'_, W>
345where
346 W: Write + Seek,
347{
348 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
350 self.writer.write(buf).inspect(|&n| {
351 self.bytes_written += n;
352 })
353 }
354
355 fn flush(&mut self) -> std::io::Result<()> {
356 self.writer.flush()
357 }
358}