How do I replace a field in a data structure?

I have this data structure:

#[derive(Debug, FromForm, Serialize, Deserialize)]
pub struct PhotoDataInput {
    pub filename: String,
    pub title_en: String,
    pub description_en: String,
    pub title_ja: String,
    pub description_ja: String,
    pub tags: String,
}

impl PhotoDataInput {
    pub fn replace_tags(&mut self, replace_tags: String) {
        self.tags = replace_tags;
    }
}

The data is accepted from web HTML post:

#[post("/publish_photo", data = "<photo_data>")]
fn publish_photo<'r>(photo_data: Result<Form<'r, PhotoDataInput>, Option<String>>) -> Redirect {
    let photo_data_input_form = photo_data.expect("Error processing submitted form data");
    let photo_data_input = photo_data_input_form.get();
    photo_actions::process_photo_data(&photo_data_input); // todo get and process result
...

and the function to process it:

`pub fn process_photo_data(photo_data: &web::PhotoDataInput) {`
...
    let tags_vector: Vec<&str> = photo_data.tags.split(',').collect();
    let tags_json = super::serde_json::to_value(tags_vector).expect("error");
    println!("tags_json: {}", tags_json); // OK, this is correct so far

    // THIS DOESN'T WORK
    photo_data.replace_tags(tags_json.to_string());

    let connection = super::database::establish_connection();
    let photo_data_doc = super::serde_json::to_value(photo_data).expect("error converting to value");
    super::database::new_photo(&connection, photo_data_doc);

Explained:

I have a web form to take in user inputs. User will typically type something like "food, movies, music" into the tags field. However, I need to convert this input into JSON array format, thus, something like "["music", "movies", "music"]" and then, replace the new JSON array string into the data structure and save into the database.

I tried to do photo_data.clone() and the compiler complained as well. I just could not get it work.

I'd appreciate if someone could show me how to replace the 'tags' in the PhotoDataInput data structure and then successfully save it into the db.

(I'm using Rocket and Diesel)

I've not used Diesel, but I have good news for your first question ("how do I replace a field in a data structure?"). Your PhotoDataInput::replace_tags implementation looks fine. I pasted your struct declaration and impl into the Playground to verify, and it works fine.

So if you're having trouble replacing the field, you may not own the data you're trying to pass in? I'm not sure, because it's not clear exactly what error(s) your getting and when. One way to help the community to help you is to post a simplified example of the problem to the Playground, although I can understand that this is difficult to do when you are talking to a database... :slight_smile:

pub fn process_photo_data(photo_data: &mut web::PhotoDataInput) {
or
pub fn process_photo_data(mut photo_data: web::PhotoDataInput) {

Sure error message should be saying something along these lines but you haven't posted.

I tried:

pub fn process_photo_data(photo_data: &mut web::PhotoDataInput) {

and I have this error:

error[E0308]: mismatched types
--> src\web.rs:87:39
|
87 | photo_actions::process_photo_data(&photo_data_input);
| ^^^^^^^^^^^^^^^^^ types differ in mutability
|
= note: expected type &mut web::PhotoDataInput
found type &&web::PhotoDataInput

error: aborting due to previous error

The calling code in src\web.rs:87:39 is:

#[post("/publish_photo", data = "<photo_data>")]
fn publish_photo<'r>(photo_data: Result<Form<'r, PhotoDataInput>, Option>) -> Redirect {
let photo_data_input_form = photo_data.expect("Error processing submitted form data");
let photo_data_input = photo_data_input_form.get();
photo_actions::process_photo_data(&photo_data_input);

I think the problem is how do I get a mutable object of photo_data_input_form.get() method?
(I can't figure this out.)


I then tried:

pub fn process_photo_data (mut photo_data: &web::PhotoDataInput) {

and it compiled fine. BUT, when I added:

photo_data.replace_tags(tags_json.to_string());

I got these errors:

error[E0596]: cannot borrow immutable borrowed content *photo_data as mutable
--> src\photo_actions.rs:45:5
|
13 | pub fn process_photo_data(mut photo_data: &web::PhotoDataInput) {
| -------------------- use &mut web::PhotoDataInput here to make mutable
...
45 | photo_data.replace_tags(tags_json.to_string());
| ^^^^^^^^^^ cannot borrow as mutable

warning: variable does not need to be mutable
--> src\photo_actions.rs:13:27
|
13 | pub fn process_photo_data(mut photo_data: &web::PhotoDataInput) {
| ---^^^^^^^^^^^
| |
| help: remove this mut
|
= note: #[warn(unused_mut)] on by default

error: aborting due to previous error

I think that by getting "photo_data.replace_tags(tags_json.to_string());" to work it will resolve my problem, but I can't figure it out.

I looked at the documentation for Rocket for Form. There is a get_mut method (you can find it on the page).

However, it does not compile:

error[E0599]: no method named get_mut found for type rocket::request::Form<'_, web::PhotoDataInput> in the current scope
--> src\web.rs:87:50
|
87 | let photo_data_input = photo_data_input_form.get_mut();
| ^^^^^^^

error: aborting due to previous error

Is that a typo in the documentation, or what is the version of Rocket which supports get_mut() method?

I think you’re supposed to do the following:

let photo_data_input_form = photo_data.expect(“Error processing submitted form data”);
let mut photo_data_input = photo_data_input_form.into_inner();
photo_actions::process_photo_data(&mut photo_data_input);

So you take the PhotoDataInput value (not a reference) out of the Form and then you can pass it as a mutable reference to process_photo_data(), or you can pass it by-value instead of mutable reference - depends on whether you need this value after process_photo_data returns.

P.S. Use triple backticks to format code snippets

1 Like

Thanks!! That works for me!!!