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 utils::*,
14 Basic, DynamicType, Error, Result, Signature,
15};
16
17struct NullWriteSeek;
18
19impl Write for NullWriteSeek {
20 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
21 Ok(buf.len())
22 }
23
24 fn flush(&mut self) -> std::io::Result<()> {
25 Ok(())
26 }
27}
28
29impl Seek for NullWriteSeek {
30 fn seek(&mut self, _pos: std::io::SeekFrom) -> std::io::Result<u64> {
31 Ok(u64::MAX) }
33}
34
35pub fn serialized_size<T>(ctxt: Context, value: &T) -> Result<Size>
50where
51 T: ?Sized + Serialize + DynamicType,
52{
53 let mut null = NullWriteSeek;
54 let signature = value.signature();
55 #[cfg(unix)]
56 let mut fds = FdList::Number(0);
57
58 let len = match ctxt.format() {
59 Format::DBus => {
60 let mut ser = DBusSerializer::<NullWriteSeek>::new(
61 &signature,
62 &mut null,
63 #[cfg(unix)]
64 &mut fds,
65 ctxt,
66 )?;
67 value.serialize(&mut ser)?;
68 ser.0.bytes_written
69 }
70 #[cfg(feature = "gvariant")]
71 Format::GVariant => {
72 let mut ser = GVSerializer::<NullWriteSeek>::new(
73 &signature,
74 &mut null,
75 #[cfg(unix)]
76 &mut fds,
77 ctxt,
78 )?;
79 value.serialize(&mut ser)?;
80 ser.0.bytes_written
81 }
82 };
83
84 let size = Size::new(len, ctxt);
85 #[cfg(unix)]
86 let size = match fds {
87 FdList::Number(n) => size.set_num_fds(n),
88 FdList::Fds(_) => unreachable!("`Fds::Fds` is not possible here"),
89 };
90
91 Ok(size)
92}
93
94pub unsafe fn to_writer<W, T>(writer: &mut W, ctxt: Context, value: &T) -> Result<Written>
120where
121 W: Write + Seek,
122 T: ?Sized + Serialize + DynamicType,
123{
124 let signature = value.signature();
125
126 to_writer_for_signature(writer, ctxt, signature, value)
127}
128
129pub fn to_bytes<T>(ctxt: Context, value: &T) -> Result<Data<'static, 'static>>
133where
134 T: ?Sized + Serialize + DynamicType,
135{
136 to_bytes_for_signature(ctxt, value.signature(), value)
137}
138
139pub unsafe fn to_writer_for_signature<W, S, T>(
156 writer: &mut W,
157 ctxt: Context,
158 signature: S,
159 value: &T,
160) -> Result<Written>
161where
162 W: Write + Seek,
163 S: TryInto<Signature>,
164 S::Error: Into<Error>,
165 T: ?Sized + Serialize,
166{
167 let signature = signature.try_into().map_err(Into::into)?;
168
169 #[cfg(unix)]
170 let mut fds = FdList::Fds(vec![]);
171
172 let len = match ctxt.format() {
173 Format::DBus => {
174 let mut ser = DBusSerializer::<W>::new(
175 &signature,
176 writer,
177 #[cfg(unix)]
178 &mut fds,
179 ctxt,
180 )?;
181 value.serialize(&mut ser)?;
182 ser.0.bytes_written
183 }
184 #[cfg(feature = "gvariant")]
185 Format::GVariant => {
186 let mut ser = GVSerializer::<W>::new(
187 &signature,
188 writer,
189 #[cfg(unix)]
190 &mut fds,
191 ctxt,
192 )?;
193 value.serialize(&mut ser)?;
194 ser.0.bytes_written
195 }
196 };
197
198 let written = Written::new(len, ctxt);
199 #[cfg(unix)]
200 let written = match fds {
201 FdList::Fds(fds) => written.set_fds(fds),
202 FdList::Number(_) => unreachable!("`Fds::Number` is not possible here"),
203 };
204
205 Ok(written)
206}
207
208pub fn to_bytes_for_signature<S, T>(
217 ctxt: Context,
218 signature: S,
219 value: &T,
220) -> Result<Data<'static, 'static>>
221where
222 S: TryInto<Signature>,
223 S::Error: Into<Error>,
224 T: ?Sized + Serialize,
225{
226 let mut cursor = std::io::Cursor::new(vec![]);
227 let ret = unsafe { to_writer_for_signature(&mut cursor, ctxt, signature, value) }?;
230 #[cfg(unix)]
231 let encoded = Data::new_fds(cursor.into_inner(), ctxt, ret.into_fds());
232 #[cfg(not(unix))]
233 let encoded = {
234 let _ = ret;
235 Data::new(cursor.into_inner(), ctxt)
236 };
237
238 Ok(encoded)
239}
240
241pub(crate) struct SerializerCommon<'ser, W> {
243 pub(crate) ctxt: Context,
244 pub(crate) writer: &'ser mut W,
245 pub(crate) bytes_written: usize,
246 #[cfg(unix)]
247 pub(crate) fds: &'ser mut FdList,
248
249 pub(crate) signature: &'ser Signature,
250
251 pub(crate) value_sign: Option<Signature>,
252
253 pub(crate) container_depths: ContainerDepths,
254}
255
256#[cfg(unix)]
257pub(crate) enum FdList {
258 Fds(Vec<OwnedFd>),
259 Number(u32),
260}
261
262impl<W> SerializerCommon<'_, W>
263where
264 W: Write + Seek,
265{
266 #[cfg(unix)]
267 pub(crate) fn add_fd(&mut self, fd: std::os::fd::RawFd) -> Result<u32> {
268 use std::os::fd::{AsRawFd, BorrowedFd};
269
270 match self.fds {
271 FdList::Fds(fds) => {
272 if let Some(idx) = fds.iter().position(|x| x.as_raw_fd() == fd) {
273 return Ok(idx as u32);
274 }
275 let idx = fds.len();
276 let fd = unsafe { BorrowedFd::borrow_raw(fd) }.try_clone_to_owned()?;
279 fds.push(fd);
280
281 Ok(idx as u32)
282 }
283 FdList::Number(n) => {
284 let idx = *n;
285 *n += 1;
286
287 Ok(idx)
288 }
289 }
290 }
291
292 pub(crate) fn add_padding(&mut self, alignment: usize) -> Result<usize> {
293 let padding = padding_for_n_bytes(self.abs_pos(), alignment);
294 if padding > 0 {
295 self.write_all(&[0u8; 8][..padding])?;
296 }
297
298 Ok(padding)
299 }
300
301 pub(crate) fn prep_serialize_basic<T>(&mut self) -> Result<()>
302 where
303 T: Basic,
304 {
305 self.add_padding(T::alignment(self.ctxt.format()))?;
306
307 Ok(())
308 }
309
310 fn abs_pos(&self) -> usize {
311 self.ctxt.position() + self.bytes_written
312 }
313}
314
315impl<W> Write for SerializerCommon<'_, W>
316where
317 W: Write + Seek,
318{
319 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
321 self.writer.write(buf).inspect(|&n| {
322 self.bytes_written += n;
323 })
324 }
325
326 fn flush(&mut self) -> std::io::Result<()> {
327 self.writer.flush()
328 }
329}