oli-obk / rust-pandoc

Apache License 2.0
51 stars 29 forks source link

Change function signatures to accommodate chaining builder calls #51

Open elaforma opened 1 year ago

elaforma commented 1 year ago

The corresponding feature request #8 has been closed as resolved, but the following does not work with rust-pandoc version 0.8.10:

Steps to reproduce

Invoke pandoc in a builder approach:

// Cargo.toml dependencies: pandoc = "0.8.10"

use pandoc::{InputFormat, InputKind, OutputFormat, OutputKind, PandocOutput};

// [...]

let pandoc_output = pandoc::Pandoc::new()
    .set_input(InputKind::Pipe(markdown.to_string()))
    .set_output(OutputKind::Pipe)
    .set_input_format(InputFormat::Markdown, Vec::new())
    .set_output_format(OutputFormat::Json, Vec::new())
    .execute()
    .expect("pandoc");

Expected outcome

Code compiles, pandoc does its thing

Actual outcome

The set_xyz() functions take and return &mut self, but execute() takes self. Therefore, chaining execute() behind a set_xyz() call leads to the following error:

error[E0507]: cannot move out of a mutable reference
    --> src/lib.rs:16:29
     |
16   |           let pandoc_output = pandoc::Pandoc::new()
     |  _____________________________^
17   | |             .set_input(InputKind::Pipe(markdown.to_string()))
18   | |             .set_output(OutputKind::Pipe)
19   | |             .set_input_format(InputFormat::Markdown, Vec::new())
20   | |             .set_output_format(OutputFormat::Json, Vec::new())
21   | |             .execute()
     | |              --------^
     | |______________|_______|
     |                |       move occurs because value has type `pandoc::Pandoc`, which does not implement the `Copy` trait
     |                value moved due to this method call
     |
note: this function takes ownership of the receiver `self`, which moves value
    --> /home/elaforma/.cargo/registry/src/github.com-1ecc6299db9ec823/pandoc-0.8.10/src/lib.rs:1212:24
     |
1212 |     pub fn execute(mut self) -> Result<PandocOutput, PandocError> {
     |                        ^^^^

There are two possible ways to solve this:

  1. Other Rust builders often have their setter functions consume and return self as well (e.g., fn set_xyz(self, xyz: XyzOptionType) -> Self)
  2. Another possibility would be to have execute() take &mut self instead

Both of these would naturally be breaking changes.