1use serde::Serialize;
2use std::io::{Seek, Write};
3
4#[cfg(unix)]
5use std::os::fd::OwnedFd;
6
7#[cfg(feature = "gvariant")]
8use crate::gvariant::Serializer as GVSerializer;
9use crate::{
10 container_depths::ContainerDepths,
11 dbus::Serializer as DBusSerializer,
12 serialized::{Context, Data, Format, Size, Written},
13 signature_parser::SignatureParser,
14 utils::*,
15 Basic, DynamicType, Error, Result, Signature, WriteBytes,
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.dynamic_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 Format::GVariant => {
73 let mut ser = GVSerializer::<NullWriteSeek>::new(
74 signature,
75 &mut null,
76 #[cfg(unix)]
77 &mut fds,
78 ctxt,
79 )?;
80 value.serialize(&mut ser)?;
81 ser.0.bytes_written
82 }
83 };
84
85 let size = Size::new(len, ctxt);
86 #[cfg(unix)]
87 let size = match fds {
88 FdList::Number(n) => size.set_num_fds(n),
89 FdList::Fds(_) => unreachable!("`Fds::Fds` is not possible here"),
90 };
91
92 Ok(size)
93}
94
95pub unsafe fn to_writer<W, T>(writer: &mut W, ctxt: Context, value: &T) -> Result<Written>
123where
124 W: Write + Seek,
125 T: ?Sized + Serialize + DynamicType,
126{
127 let signature = value.dynamic_signature();
128
129 to_writer_for_signature(writer, ctxt, &signature, value)
130}
131
132pub fn to_bytes<T>(ctxt: Context, value: &T) -> Result<Data<'static, 'static>>
136where
137 T: ?Sized + Serialize + DynamicType,
138{
139 to_bytes_for_signature(ctxt, value.dynamic_signature(), value)
140}
141
142pub unsafe fn to_writer_for_signature<'s, W, S, T>(
159 writer: &mut W,
160 ctxt: Context,
161 signature: S,
162 value: &T,
163) -> Result<Written>
164where
165 W: Write + Seek,
166 S: TryInto<Signature<'s>>,
167 S::Error: Into<Error>,
168 T: ?Sized + Serialize,
169{
170 #[cfg(unix)]
171 let mut fds = FdList::Fds(vec![]);
172
173 let len = match ctxt.format() {
174 Format::DBus => {
175 let mut ser = DBusSerializer::<W>::new(
176 signature,
177 writer,
178 #[cfg(unix)]
179 &mut fds,
180 ctxt,
181 )?;
182 value.serialize(&mut ser)?;
183 ser.0.bytes_written
184 }
185 #[cfg(feature = "gvariant")]
186 Format::GVariant => {
187 let mut ser = GVSerializer::<W>::new(
188 signature,
189 writer,
190 #[cfg(unix)]
191 &mut fds,
192 ctxt,
193 )?;
194 value.serialize(&mut ser)?;
195 ser.0.bytes_written
196 }
197 };
198
199 let written = Written::new(len, ctxt);
200 #[cfg(unix)]
201 let written = match fds {
202 FdList::Fds(fds) => written.set_fds(fds),
203 FdList::Number(_) => unreachable!("`Fds::Number` is not possible here"),
204 };
205
206 Ok(written)
207}
208
209pub fn to_bytes_for_signature<'s, S, T>(
218 ctxt: Context,
219 signature: S,
220 value: &T,
221) -> Result<Data<'static, 'static>>
222where
223 S: TryInto<Signature<'s>>,
224 S::Error: Into<Error>,
225 T: ?Sized + Serialize,
226{
227 let mut cursor = std::io::Cursor::new(vec![]);
228 let ret = unsafe { to_writer_for_signature(&mut cursor, ctxt, signature, value) }?;
231 #[cfg(unix)]
232 let encoded = Data::new_fds(cursor.into_inner(), ctxt, ret.into_fds());
233 #[cfg(not(unix))]
234 let encoded = {
235 let _ = ret;
236 Data::new(cursor.into_inner(), ctxt)
237 };
238
239 Ok(encoded)
240}
241
242pub(crate) struct SerializerCommon<'ser, 'sig, W> {
244 pub(crate) ctxt: Context,
245 pub(crate) writer: &'ser mut W,
246 pub(crate) bytes_written: usize,
247 #[cfg(unix)]
248 pub(crate) fds: &'ser mut FdList,
249
250 pub(crate) sig_parser: SignatureParser<'sig>,
251
252 pub(crate) value_sign: Option<Signature<'static>>,
253
254 pub(crate) container_depths: ContainerDepths,
255}
256
257#[cfg(unix)]
258pub(crate) enum FdList {
259 Fds(Vec<OwnedFd>),
260 Number(u32),
261}
262
263impl<'ser, 'sig, W> SerializerCommon<'ser, 'sig, W>
264where
265 W: Write + Seek,
266{
267 #[cfg(unix)]
268 pub(crate) fn add_fd(&mut self, fd: std::os::fd::RawFd) -> Result<u32> {
269 use std::os::fd::{AsRawFd, BorrowedFd};
270
271 match self.fds {
272 FdList::Fds(fds) => {
273 if let Some(idx) = fds.iter().position(|x| x.as_raw_fd() == fd) {
274 return Ok(idx as u32);
275 }
276 let idx = fds.len();
277 let fd = unsafe { BorrowedFd::borrow_raw(fd) }.try_clone_to_owned()?;
280 fds.push(fd);
281
282 Ok(idx as u32)
283 }
284 FdList::Number(n) => {
285 let idx = *n;
286 *n += 1;
287
288 Ok(idx)
289 }
290 }
291 }
292
293 pub(crate) fn add_padding(&mut self, alignment: usize) -> Result<usize> {
294 let padding = padding_for_n_bytes(self.abs_pos(), alignment);
295 if padding > 0 {
296 let byte = [0_u8; 1];
297 for _ in 0..padding {
298 self.write_all(&byte)
299 .map_err(|e| Error::InputOutput(e.into()))?;
300 }
301 }
302
303 Ok(padding)
304 }
305
306 pub(crate) fn prep_serialize_basic<T>(&mut self) -> Result<()>
307 where
308 T: Basic,
309 {
310 self.sig_parser.skip_char()?;
311 self.add_padding(T::alignment(self.ctxt.format()))?;
312
313 Ok(())
314 }
315
316 pub(crate) fn prep_serialize_enum_variant(&mut self, variant_index: u32) -> Result<()> {
320 let signature = self.sig_parser.next_signature()?;
322 if self.sig_parser.next_char()? != STRUCT_SIG_START_CHAR {
323 return Err(Error::SignatureMismatch(
324 signature.to_owned(),
325 format!("expected `{STRUCT_SIG_START_CHAR}`"),
326 ));
327 }
328
329 let alignment = alignment_for_signature(&signature, self.ctxt.format())?;
330 self.add_padding(alignment)?;
331
332 self.write_u32(self.ctxt.endian(), variant_index)
334 .map_err(|e| Error::InputOutput(e.into()))?;
335
336 self.sig_parser.skip_chars(2)?;
338
339 Ok(())
340 }
341
342 fn abs_pos(&self) -> usize {
343 self.ctxt.position() + self.bytes_written
344 }
345}
346
347impl<'ser, 'sig, W> Write for SerializerCommon<'ser, 'sig, W>
348where
349 W: Write + Seek,
350{
351 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
353 self.writer.write(buf).map(|n| {
354 self.bytes_written += n;
355
356 n
357 })
358 }
359
360 fn flush(&mut self) -> std::io::Result<()> {
361 self.writer.flush()
362 }
363}