Serde structure invoking Copy?

Code:

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct ProjectSettings {
    #[serde(rename = "short-id")]
    pub short_id: String,
    #[serde(rename = "full-id")]
    pub full_id: String,
}

pub fn read_project_settings<S: AsRef<str>>(dir: S) -> Result<ProjectSettings, ProjectSettingsError> {
    let project_settings_path = Path::new(dir.as_ref()).join("Rialight.toml");
    // ...
    Ok(ProjectSettings {
        // problem here:
        short_id: project_settings.short_id.clone(),
        full_id: project_settings.full_id.clone(),
    })
}

Problem:

borrow of moved value: `project_settings.short_id`
move occurs because `project_settings.short_id` has type `std::string::String`,
which does not implement the `Copy` trait
rustc E0382
lib.rs(30, 21): value moved here

Looks like something in the // ... consumed project_settings.short_id or all of project_settings. There's not enough context for me to guess what's going on beyond that.

1 Like

Whoops, I forgot to post more. Here's the full function:

pub fn read_project_settings<S: AsRef<str>>(dir: S) -> Result<ProjectSettings, ProjectSettingsError> {
    let project_settings_path = Path::new(dir.as_ref()).join("Rialight.toml");
    if !(project_settings_path.exists() && project_settings_path.is_file()) {
        return Err(ProjectSettingsError::NotFound);
    }
    let project_settings: ProjectSettings = toml::from_str(std::str::from_utf8(&fs::read(project_settings_path).unwrap()).unwrap()).unwrap();
    if !is_id_valid(project_settings.short_id) {
        return Err(ProjectSettingsError::InvalidShortId);
    }
    if !is_id_valid(project_settings.full_id) {
        return Err(ProjectSettingsError::InvalidFullId);
    }
    Ok(ProjectSettings {
        short_id: project_settings.short_id.clone(),
        full_id: project_settings.full_id.clone(),
    })
}

Try

    if !is_id_valid(&project_settings.short_id) {
// n.b.             ^
        return Err(ProjectSettingsError::InvalidShortId);
    }
    if !is_id_valid(&project_settings.full_id) {
// n.b.             ^
        return Err(ProjectSettingsError::InvalidFullId);
    }
    // no cloning
    Ok(project_settings)

Or if that doesn't work, you could do

    // Clone here instead
    if !is_id_valid(project_settings.short_id.clone()) {
        return Err(ProjectSettingsError::InvalidShortId);
    }
    if !is_id_valid(project_settings.full_id.clone()) {
        return Err(ProjectSettingsError::InvalidFullId);
    }
    // still no cloning here
    Ok(project_settings)

But probably is_id_valid should be rewritten to take a &str instead of a String instead (so that the first suggestion works).

4 Likes

Thanks!

You might also want to read this chapter in the book to learn more about non-Copy data more generally. The error could be rephrased "you tried to use something after you moved it, but you can only do that with types that are Copy... and that type isn't Copy."

4 Likes