nyquest_interface/body/
multipart.rs

1//! Multipart form data definitions for HTTP requests.
2//!
3//! This module defines types for creating multipart/form-data bodies,
4//! which allow sending complex data including files in HTTP requests.
5
6use std::{borrow::Cow, fmt::Debug};
7
8use super::StreamReader;
9
10/// Represents a part in a multipart form.
11///
12/// Each part has a name, optional filename, content type, and a body,
13/// along with optional additional headers.
14pub struct Part<S> {
15    /// Additional headers for this part.
16    pub headers: Vec<(Cow<'static, str>, Cow<'static, str>)>,
17    /// Name of the form field.
18    pub name: Cow<'static, str>,
19    /// Optional filename for file parts.
20    pub filename: Option<Cow<'static, str>>,
21    /// MIME content type for this part.
22    pub content_type: Cow<'static, str>,
23    /// Body content for this part.
24    pub body: PartBody<S>,
25}
26
27/// Body content for a multipart form part.
28///
29/// This can be either raw bytes or a stream.
30pub enum PartBody<S> {
31    /// Raw byte content.
32    Bytes {
33        /// The bytes that make up this part's content.
34        content: Cow<'static, [u8]>,
35    },
36    /// Streaming content for larger part bodies.
37    #[doc(hidden)]
38    Stream(StreamReader<S>),
39}
40
41impl<S> Debug for Part<S>
42where
43    S: Debug,
44{
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        f.debug_struct("Part")
47            .field("headers", &self.headers)
48            .field("name", &self.name)
49            .field("filename", &self.filename)
50            .field("content_type", &self.content_type)
51            .field("body", &self.body)
52            .finish()
53    }
54}
55
56impl<S> Debug for PartBody<S>
57where
58    S: Debug,
59{
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        match self {
62            PartBody::Bytes { content } => f
63                .debug_struct("PartBody::Bytes")
64                .field("content", content)
65                .finish(),
66            PartBody::Stream(stream) => f
67                .debug_struct("PartBody::Stream")
68                .field("stream", stream)
69                .finish(),
70        }
71    }
72}
73impl<S> Clone for Part<S>
74where
75    S: Clone,
76{
77    fn clone(&self) -> Self {
78        Self {
79            headers: self.headers.clone(),
80            name: self.name.clone(),
81            filename: self.filename.clone(),
82            content_type: self.content_type.clone(),
83            body: self.body.clone(),
84        }
85    }
86}
87impl<S> Clone for PartBody<S>
88where
89    S: Clone,
90{
91    fn clone(&self) -> Self {
92        match self {
93            PartBody::Bytes { content } => PartBody::Bytes {
94                content: content.clone(),
95            },
96            PartBody::Stream(stream) => PartBody::Stream(stream.clone()),
97        }
98    }
99}