Calling `form.prepare()?.boundary()` twice panics
Creating a form outside of a loop and then calling let prepared_fields = form.prepare()?; and let boundary = prepared_fields.boundary(); in a loop panics on the second time.
Function the crash occurs in:
https://github.com/abonander/multipart/blob/4a4104d2c5241dd9702359d4e2e91114408afbb0/src/client/lazy.rs#L298-L305
Backtrace:
thread 'main' panicked at 'attempt to subtract with overflow', /home/konsti/.cargo/registry/src/github.com-1ecc6299db9ec823/multipart-0.16.1/src/client/lazy.rs:303:24
stack backtrace:
0: backtrace::backtrace::libunwind::trace
at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.34/src/backtrace/libunwind.rs:88
1: backtrace::backtrace::trace_unsynchronized
at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.34/src/backtrace/mod.rs:66
2: std::sys_common::backtrace::_print
at src/libstd/sys_common/backtrace.rs:47
3: std::sys_common::backtrace::print
at src/libstd/sys_common/backtrace.rs:36
4: std::panicking::default_hook::{{closure}}
at src/libstd/panicking.rs:200
5: std::panicking::default_hook
at src/libstd/panicking.rs:214
6: std::panicking::rust_panic_with_hook
at src/libstd/panicking.rs:477
7: std::panicking::continue_panic_fmt
at src/libstd/panicking.rs:384
8: rust_begin_unwind
at src/libstd/panicking.rs:311
9: core::panicking::panic_fmt
at src/libcore/panicking.rs:85
10: core::panicking::panic
at src/libcore/panicking.rs:49
11: multipart::client::lazy::PreparedFields::boundary
at /home/konsti/.cargo/registry/src/github.com-1ecc6299db9ec823/multipart-0.16.1/src/client/lazy.rs:303
12: pyo3_pack::upload::upload
at src/upload.rs:93
13: pyo3_pack::upload_ui::{{closure}}
at src/main.rs:326
14: <core::iter::adapters::Map<I,F> as core::iter::traits::iterator::Iterator>::try_fold::{{closure}}
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/iter/adapters/mod.rs:615
15: <core::slice::Iter<T> as core::iter::traits::iterator::Iterator>::try_fold
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/slice/mod.rs:3187
16: <core::iter::adapters::Map<I,F> as core::iter::traits::iterator::Iterator>::try_fold
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/iter/adapters/mod.rs:615
17: <core::iter::adapters::ResultShunt<I,E> as core::iter::traits::iterator::Iterator>::try_fold
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/iter/adapters/mod.rs:2234
18: core::iter::traits::iterator::Iterator::fold
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/iter/traits/iterator.rs:1783
19: core::iter::traits::iterator::Iterator::for_each
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/iter/traits/iterator.rs:602
20: core::unit::<impl core::iter::traits::collect::FromIterator<()> for ()>::from_iter
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/unit.rs:19
21: core::iter::traits::iterator::Iterator::collect
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/iter/traits/iterator.rs:1464
22: <core::result::Result<V,E> as core::iter::traits::collect::FromIterator<core::result::Result<A,E>>>::from_iter::{{closure}}
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/result.rs:1346
23: core::iter::adapters::process_results
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/iter/adapters/mod.rs:2206
24: <core::result::Result<V,E> as core::iter::traits::collect::FromIterator<core::result::Result<A,E>>>::from_iter
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/result.rs:1346
25: core::iter::traits::iterator::Iterator::collect
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libcore/iter/traits/iterator.rs:1464
26: pyo3_pack::upload_ui
at src/main.rs:323
27: pyo3_pack::run
at src/main.rs:410
28: pyo3_pack::main
at src/main.rs:485
29: std::rt::lang_start::{{closure}}
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libstd/rt.rs:64
30: std::rt::lang_start_internal::{{closure}}
at src/libstd/rt.rs:49
31: std::panicking::try::do_call
at src/libstd/panicking.rs:296
32: __rust_maybe_catch_panic
at src/libpanic_unwind/lib.rs:80
33: std::panicking::try
at src/libstd/panicking.rs:275
34: std::panic::catch_unwind
at src/libstd/panic.rs:394
35: std::rt::lang_start_internal
at src/libstd/rt.rs:48
36: std::rt::lang_start
at /rustc/ad7c55e1fc55d9af4787b285cec1c64e3480ae84/src/libstd/rt.rs:64
37: main
38: __libc_start_main
39: _start
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
@konstin leaving this open cause I'm not sure how to address it but .prepare() is not meant to be called more than once in a row; the fields you set in the form were moved the first time you called it.
This panic is occurring because boundary is empty; if there are no fields in the request then a boundary doesn't need to be created. A simple fix would be to not perform the slicing operation if the boundary is empty.
I don't really have a good reason for why .prepare() doesn't take the Multipart by-value except that I thought people might want to reuse the internal allocation to build another request. Oh, also because the other methods take &mut self and return &mut Self so this can all fit into one call chain.
I think .prepare() consuming Mutlitpart would be a good idea as it's already consuming the contents. boundary() not slicing or at least explicitly panicing with an error message would also be helpful.