pub struct PartMetadata { /* private fields */ }
Expand description

Multipart 表单组件元信息

Implementations§

设置表单组件的 MIME 类型

Examples found in repository?
src/client/request/multipart.rs (line 286)
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
        pub fn file_path<S: AsRef<OsStr> + ?Sized>(path: &S) -> IoResult<Self> {
            let path = Path::new(path);
            let file = File::open(path)?;
            let mut metadata = PartMetadata::default().mime(mime_guess::from_path(path).first_or_octet_stream());
            if let Some(file_name) = path.file_name() {
                let file_name = match file_name.to_string_lossy() {
                    Cow::Borrowed(str) => FileName::from(str),
                    Cow::Owned(string) => FileName::from(string),
                };
                metadata = metadata.file_name(file_name);
            }
            Ok(SyncPart::stream(file).metadata(metadata))
        }
    }

    /// 阻塞 Multipart
    pub type SyncMultipart<'a> = Multipart<SyncPart<'a>>;

    impl<'a> SyncMultipart<'a> {
        pub(in super::super) fn into_read(mut self) -> Box<dyn Read + 'a> {
            if self.fields.is_empty() {
                return Box::new(Cursor::new([]));
            }

            let (name, part) = self.fields.pop_front().unwrap();
            let chain = Box::new(self.part_stream(&name, part)) as Box<dyn Read + 'a>;
            let fields = take(&mut self.fields);
            Box::new(
                fields
                    .into_iter()
                    .fold(chain, |readable, (name, part)| {
                        Box::new(readable.chain(self.part_stream(&name, part))) as Box<dyn Read + 'a>
                    })
                    .chain(Cursor::new(b"--"))
                    .chain(Cursor::new(self.boundary.to_owned()))
                    .chain(Cursor::new(b"--\r\n")),
            )
        }

        fn part_stream(&self, name: &str, part: SyncPart<'a>) -> impl Read + 'a {
            Cursor::new(b"--")
                .chain(Cursor::new(self.boundary.to_owned()))
                .chain(Cursor::new(b"\r\n"))
                .chain(Cursor::new(encode_headers(name, &part.meta)))
                .chain(Cursor::new(b"\r\n\r\n"))
                .chain(part.body)
                .chain(Cursor::new(b"\r\n"))
        }
    }

    impl Read for SyncPartBody<'_> {
        #[inline]
        fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
            match &mut self.0 {
                SyncPartBodyInner::Bytes(bytes) => bytes.read(buf),
                SyncPartBodyInner::Stream(stream) => stream.read(buf),
            }
        }
    }
}
pub use sync_part::{SyncMultipart, SyncPart, SyncPartBody};

#[cfg(feature = "async")]
mod async_part {
    use super::*;
    use async_std::{fs::File, path::Path};
    use futures::io::{AsyncRead, AsyncReadExt, Cursor};
    use std::{
        fmt::{self, Debug},
        io::Result as IoResult,
        mem::take,
        pin::Pin,
        task::{Context, Poll},
    };

    type AsyncStream<'a> = Box<dyn AsyncRead + Send + Unpin + 'a>;

    enum AsyncPartBodyInner<'a> {
        Bytes(Cursor<Cow<'a, [u8]>>),
        Stream(AsyncStream<'a>),
    }

    impl Debug for AsyncPartBodyInner<'_> {
        #[inline]
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            match self {
                Self::Bytes(bytes) => f.debug_tuple("Bytes").field(bytes).finish(),
                Self::Stream(_) => f.debug_tuple("Stream").finish(),
            }
        }
    }

    /// 异步 Multipart 表单组件请求体
    #[derive(Debug)]
    #[cfg_attr(feature = "docs", doc(cfg(feature = "async")))]
    pub struct AsyncPartBody<'a>(AsyncPartBodyInner<'a>);

    /// 异步 Multipart 表单组件
    #[cfg_attr(feature = "docs", doc(cfg(feature = "async")))]
    pub type AsyncPart<'a> = Part<AsyncPartBody<'a>>;

    impl<'a> AsyncPart<'a> {
        /// 设置异步 Multipart 的请求体为字符串
        #[inline]
        #[must_use]
        pub fn text(value: impl Into<Cow<'a, str>>) -> Self {
            let bytes = match value.into() {
                Cow::Borrowed(slice) => Cow::Borrowed(slice.as_bytes()),
                Cow::Owned(string) => Cow::Owned(string.into_bytes()),
            };
            Self {
                body: AsyncPartBody(AsyncPartBodyInner::Bytes(Cursor::new(bytes))),
                meta: Default::default(),
            }
        }

        /// 设置异步 Multipart 的请求体为内存数据
        #[inline]
        #[must_use]
        pub fn bytes(value: impl Into<Cow<'a, [u8]>>) -> Self {
            Self {
                body: AsyncPartBody(AsyncPartBodyInner::Bytes(Cursor::new(value.into()))),
                meta: Default::default(),
            }
        }

        /// 设置异步 Multipart 的请求体为异步输入流
        #[inline]
        #[must_use]
        pub fn stream(value: impl AsyncRead + Send + Unpin + 'a) -> Self {
            Self {
                body: AsyncPartBody(AsyncPartBodyInner::Stream(Box::new(value))),
                meta: Default::default(),
            }
        }

        /// 设置异步 Multipart 的请求体为文件
        pub async fn file_path<S: AsRef<OsStr> + ?Sized>(path: &S) -> IoResult<AsyncPart<'a>> {
            let path = Path::new(path);
            let file = File::open(&path).await?;
            let mut metadata = PartMetadata::default().mime(mime_guess::from_path(path).first_or_octet_stream());
            if let Some(file_name) = path.file_name() {
                let file_name = match file_name.to_string_lossy() {
                    Cow::Borrowed(str) => FileName::from(str),
                    Cow::Owned(string) => FileName::from(string),
                };
                metadata = metadata.file_name(file_name);
            }
            Ok(AsyncPart::stream(file).metadata(metadata))
        }

添加表单组件的 HTTP 头

Examples found in repository?
src/client/request/multipart.rs (line 163)
162
163
164
    pub fn mime(self, mime: Mime) -> Self {
        self.add_header(CONTENT_TYPE, HeaderValue::from_str(mime.as_ref()).unwrap())
    }

设置表单组件的文件名

Examples found in repository?
src/client/request/multipart.rs (line 292)
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
        pub fn file_path<S: AsRef<OsStr> + ?Sized>(path: &S) -> IoResult<Self> {
            let path = Path::new(path);
            let file = File::open(path)?;
            let mut metadata = PartMetadata::default().mime(mime_guess::from_path(path).first_or_octet_stream());
            if let Some(file_name) = path.file_name() {
                let file_name = match file_name.to_string_lossy() {
                    Cow::Borrowed(str) => FileName::from(str),
                    Cow::Owned(string) => FileName::from(string),
                };
                metadata = metadata.file_name(file_name);
            }
            Ok(SyncPart::stream(file).metadata(metadata))
        }
    }

    /// 阻塞 Multipart
    pub type SyncMultipart<'a> = Multipart<SyncPart<'a>>;

    impl<'a> SyncMultipart<'a> {
        pub(in super::super) fn into_read(mut self) -> Box<dyn Read + 'a> {
            if self.fields.is_empty() {
                return Box::new(Cursor::new([]));
            }

            let (name, part) = self.fields.pop_front().unwrap();
            let chain = Box::new(self.part_stream(&name, part)) as Box<dyn Read + 'a>;
            let fields = take(&mut self.fields);
            Box::new(
                fields
                    .into_iter()
                    .fold(chain, |readable, (name, part)| {
                        Box::new(readable.chain(self.part_stream(&name, part))) as Box<dyn Read + 'a>
                    })
                    .chain(Cursor::new(b"--"))
                    .chain(Cursor::new(self.boundary.to_owned()))
                    .chain(Cursor::new(b"--\r\n")),
            )
        }

        fn part_stream(&self, name: &str, part: SyncPart<'a>) -> impl Read + 'a {
            Cursor::new(b"--")
                .chain(Cursor::new(self.boundary.to_owned()))
                .chain(Cursor::new(b"\r\n"))
                .chain(Cursor::new(encode_headers(name, &part.meta)))
                .chain(Cursor::new(b"\r\n\r\n"))
                .chain(part.body)
                .chain(Cursor::new(b"\r\n"))
        }
    }

    impl Read for SyncPartBody<'_> {
        #[inline]
        fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
            match &mut self.0 {
                SyncPartBodyInner::Bytes(bytes) => bytes.read(buf),
                SyncPartBodyInner::Stream(stream) => stream.read(buf),
            }
        }
    }
}
pub use sync_part::{SyncMultipart, SyncPart, SyncPartBody};

#[cfg(feature = "async")]
mod async_part {
    use super::*;
    use async_std::{fs::File, path::Path};
    use futures::io::{AsyncRead, AsyncReadExt, Cursor};
    use std::{
        fmt::{self, Debug},
        io::Result as IoResult,
        mem::take,
        pin::Pin,
        task::{Context, Poll},
    };

    type AsyncStream<'a> = Box<dyn AsyncRead + Send + Unpin + 'a>;

    enum AsyncPartBodyInner<'a> {
        Bytes(Cursor<Cow<'a, [u8]>>),
        Stream(AsyncStream<'a>),
    }

    impl Debug for AsyncPartBodyInner<'_> {
        #[inline]
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            match self {
                Self::Bytes(bytes) => f.debug_tuple("Bytes").field(bytes).finish(),
                Self::Stream(_) => f.debug_tuple("Stream").finish(),
            }
        }
    }

    /// 异步 Multipart 表单组件请求体
    #[derive(Debug)]
    #[cfg_attr(feature = "docs", doc(cfg(feature = "async")))]
    pub struct AsyncPartBody<'a>(AsyncPartBodyInner<'a>);

    /// 异步 Multipart 表单组件
    #[cfg_attr(feature = "docs", doc(cfg(feature = "async")))]
    pub type AsyncPart<'a> = Part<AsyncPartBody<'a>>;

    impl<'a> AsyncPart<'a> {
        /// 设置异步 Multipart 的请求体为字符串
        #[inline]
        #[must_use]
        pub fn text(value: impl Into<Cow<'a, str>>) -> Self {
            let bytes = match value.into() {
                Cow::Borrowed(slice) => Cow::Borrowed(slice.as_bytes()),
                Cow::Owned(string) => Cow::Owned(string.into_bytes()),
            };
            Self {
                body: AsyncPartBody(AsyncPartBodyInner::Bytes(Cursor::new(bytes))),
                meta: Default::default(),
            }
        }

        /// 设置异步 Multipart 的请求体为内存数据
        #[inline]
        #[must_use]
        pub fn bytes(value: impl Into<Cow<'a, [u8]>>) -> Self {
            Self {
                body: AsyncPartBody(AsyncPartBodyInner::Bytes(Cursor::new(value.into()))),
                meta: Default::default(),
            }
        }

        /// 设置异步 Multipart 的请求体为异步输入流
        #[inline]
        #[must_use]
        pub fn stream(value: impl AsyncRead + Send + Unpin + 'a) -> Self {
            Self {
                body: AsyncPartBody(AsyncPartBodyInner::Stream(Box::new(value))),
                meta: Default::default(),
            }
        }

        /// 设置异步 Multipart 的请求体为文件
        pub async fn file_path<S: AsRef<OsStr> + ?Sized>(path: &S) -> IoResult<AsyncPart<'a>> {
            let path = Path::new(path);
            let file = File::open(&path).await?;
            let mut metadata = PartMetadata::default().mime(mime_guess::from_path(path).first_or_octet_stream());
            if let Some(file_name) = path.file_name() {
                let file_name = match file_name.to_string_lossy() {
                    Cow::Borrowed(str) => FileName::from(str),
                    Cow::Owned(string) => FileName::from(string),
                };
                metadata = metadata.file_name(file_name);
            }
            Ok(AsyncPart::stream(file).metadata(metadata))
        }

Trait Implementations§

Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Extends a collection with the contents of an iterator. Read more
🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more
Extends a collection with the contents of an iterator. Read more
🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more

Returns the argument unchanged.

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Instruments this type with the current Span, returning an Instrumented wrapper. Read more

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe function.
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe function.
Should always be Self
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release builds.
Calls .tap_borrow() only in debug builds, and is erased in release builds.
Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Calls .tap_ref() only in debug builds, and is erased in release builds.
Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Calls .tap_deref() only in debug builds, and is erased in release builds.
Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more