message: Implement `RustDocTargetData`
  This intends to be a helper structure similar to
  `RustTargetData` which includes helper functions
  which are useful for interacting with the rustdoc
  fingerprint files among other things.
diff: @@ -3,8 +3,12 @@ use crate::core::resolver::{HasDevUnits, ResolveOpts};
  use crate::core::{Shell, Workspace};
  use crate::ops;
  use crate::util::CargoResult;
  +use serde::{Deserialize, Serialize};
  +use serde_json::{from_str, to_writer};
  use std::collections::HashMap;
  -use std::path::Path;
  +use std::fs::File;
  +use std::io::Read;
  +use std::path::{Path, PathBuf};
  use std::process::Command;
  /// Strongly typed options for the `cargo doc` command.
  @@ -75,6 +79,15 @@ pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
  None
  };
  + // Before compiling, we need to make sure that if there were any previous docs
  + // already compiled, they were compiled with the same Rustc version that we're currently
  + // using. Otherways we must remove the `doc/` folder and compile again.
  + //
  + // This is important because the .js/.html&.css files that are generated by Rustc don't have
  + // any versioning. Therefore, we can fall in weird bugs and behaviours if we mix different
  + // compiler versions of these js/.html&.css files.
  + check_rustdoc_appropiate_versioning(ws, &target_data)?;
  +
  let compilation = ops::compile(ws, &options.compile_opts)?;
  if let Some(kind) = open_kind {
  @@ -117,3 +130,27 @@ fn open_docs(path: &Path, shell: &mut Shell) -> CargoResult<()> {
  Ok(())
  }
  +
  +#[derive(Debug, Serialize, Deserialize)]
  +pub struct RustDocTargetData {
  + rustc_verbose_version: String,
  +}
  +
  +impl RustDocTargetData {
  + pub fn with_actual_rustc_version(rustc_verbose_version: &str) -> Self {
  + Self {
  + rustc_verbose_version: rustc_verbose_version.to_string(),
  + }
  + }
  +
  + pub fn path_to_fingerprint(ws: &Workspace<'_>) -> PathBuf {
  + ws.root().join("target").join(".rustdoc_fingerprint.json")
  + }
  +
  + pub fn from_file(file: &mut File) -> anyhow::Result<Self> {
  + let mut contents = String::new();
  + file.read_to_string(&mut contents)?;
  + let rustdoc_target_data: Self = from_str(&contents)?;
  + Ok(rustdoc_target_data)
  + }
  +}
  