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 Basic, DynamicType, Error, Result, Signature,
11 container_depths::ContainerDepths,
12 dbus::Serializer as DBusSerializer,
13 serialized::{Context, Data, Format, Size, Written},
14 utils::*,
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 unsafe {
125 let signature = value.signature();
126
127 to_writer_for_signature(writer, ctxt, signature, value)
128 }
129}
130
131pub fn to_bytes<T>(ctxt: Context, value: &T) -> Result<Data<'static, 'static>>
135where
136 T: ?Sized + Serialize + DynamicType,
137{
138 to_bytes_for_signature(ctxt, value.signature(), value)
139}
140
141pub unsafe fn to_writer_for_signature<W, S, T>(
158 writer: &mut W,
159 ctxt: Context,
160 signature: S,
161 value: &T,
162) -> Result<Written>
163where
164 W: Write + Seek,
165 S: TryInto<Signature>,
166 S::Error: Into<Error>,
167 T: ?Sized + Serialize,
168{
169 let signature = signature.try_into().map_err(Into::into)?;
170
171 #[cfg(unix)]
172 let mut fds = FdList::Fds(vec![]);
173
174 let len = match ctxt.format() {
175 Format::DBus => {
176 let mut ser = DBusSerializer::<W>::new(
177 &signature,
178 writer,
179 #[cfg(unix)]
180 &mut fds,
181 ctxt,
182 )?;
183 value.serialize(&mut ser)?;
184 ser.0.bytes_written
185 }
186 #[cfg(feature = "gvariant")]
187 Format::GVariant => {
188 let mut ser = GVSerializer::<W>::new(
189 &signature,
190 writer,
191 #[cfg(unix)]
192 &mut fds,
193 ctxt,
194 )?;
195 value.serialize(&mut ser)?;
196 ser.0.bytes_written
197 }
198 };
199
200 let written = Written::new(len, ctxt);
201 #[cfg(unix)]
202 let written = match fds {
203 FdList::Fds(fds) => written.set_fds(fds),
204 FdList::Number(_) => unreachable!("`Fds::Number` is not possible here"),
205 };
206
207 Ok(written)
208}
209
210pub fn to_bytes_for_signature<S, T>(
216 ctxt: Context,
217 signature: S,
218 value: &T,
219) -> Result<Data<'static, 'static>>
220where
221 S: TryInto<Signature>,
222 S::Error: Into<Error>,
223 T: ?Sized + Serialize,
224{
225 let mut cursor = std::io::Cursor::new(vec![]);
226 let ret = unsafe { to_writer_for_signature(&mut cursor, ctxt, signature, value) }?;
229 #[cfg(unix)]
230 let encoded = Data::new_fds(cursor.into_inner(), ctxt, ret.into_fds());
231 #[cfg(not(unix))]
232 let encoded = {
233 let _ = ret;
234 Data::new(cursor.into_inner(), ctxt)
235 };
236
237 Ok(encoded)
238}
239
240pub(crate) struct SerializerCommon<'ser, W> {
242 pub(crate) ctxt: Context,
243 pub(crate) writer: &'ser mut W,
244 pub(crate) bytes_written: usize,
245 #[cfg(unix)]
246 pub(crate) fds: &'ser mut FdList,
247
248 pub(crate) signature: &'ser Signature,
249
250 pub(crate) value_sign: Option<Signature>,
251
252 pub(crate) container_depths: ContainerDepths,
253}
254
255#[cfg(unix)]
256pub(crate) enum FdList {
257 Fds(Vec<OwnedFd>),
258 Number(u32),
259}
260
261impl<W> SerializerCommon<'_, W>
262where
263 W: Write + Seek,
264{
265 #[cfg(unix)]
266 pub(crate) fn add_fd(&mut self, fd: std::os::fd::RawFd) -> Result<u32> {
267 use std::os::fd::{AsRawFd, BorrowedFd};
268
269 match self.fds {
270 FdList::Fds(fds) => {
271 if let Some(idx) = fds.iter().position(|x| x.as_raw_fd() == fd) {
272 return Ok(idx as u32);
273 }
274 let idx = fds.len();
275 let fd = unsafe { BorrowedFd::borrow_raw(fd) }.try_clone_to_owned()?;
278 fds.push(fd);
279
280 Ok(idx as u32)
281 }
282 FdList::Number(n) => {
283 let idx = *n;
284 *n += 1;
285
286 Ok(idx)
287 }
288 }
289 }
290
291 pub(crate) fn add_padding(&mut self, alignment: usize) -> Result<usize> {
292 let padding = padding_for_n_bytes(self.abs_pos(), alignment);
293 if padding > 0 {
294 self.write_all(&[0u8; 8][..padding])?;
295 }
296
297 Ok(padding)
298 }
299
300 pub(crate) fn prep_serialize_basic<T>(&mut self) -> Result<()>
301 where
302 T: Basic,
303 {
304 self.add_padding(T::alignment(self.ctxt.format()))?;
305
306 Ok(())
307 }
308
309 fn abs_pos(&self) -> usize {
310 self.ctxt.position() + self.bytes_written
311 }
312}
313
314impl<W> Write for SerializerCommon<'_, W>
315where
316 W: Write + Seek,
317{
318 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
320 self.writer.write(buf).inspect(|&n| {
321 self.bytes_written += n;
322 })
323 }
324
325 fn flush(&mut self) -> std::io::Result<()> {
326 self.writer.flush()
327 }
328}