You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: cache_manifest.rs
    path of file: ./repos/dprint/crates/dprint/src/plugins
    
    the code of the file until where you have to start completion: use serde::Deserialize;
use serde::Serialize;
use std::collections::HashMap;
use std::path::PathBuf;

use anyhow::Result;
use dprint_core::plugins::PluginInfo;

use super::implementations::WASMER_COMPILER_VERSION;
use crate::environment::Environment;

const PLUGIN_CACHE_SCHEMA_VERSION: usize = 8;

#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PluginCacheManifest {
  schema_version: usize,
  wasm_cache_version: String,
  plugins: HashMap<String, PluginCacheManifestItem>,
}

impl PluginCacheManifest {
  pub(super) fn new() -> PluginCacheManifest {
    PluginCacheManifest {
      schema_version: PLUGIN_CACHE_SCHEMA_VERSION,
      wasm_cache_version: WASMER_COMPILER_VERSION.to_string(),
      plugins: HashMap::new(),
    }
  }

  pub fn add_item(&mut self, key: String, item: PluginCacheManifestItem) {
    self.plugins.insert(key, item);
  }

  pub fn get_item(&self, key: &str) -> Option<&PluginCacheManifestItem> {
    self.plugins.get(key)
  }

  pub fn remove_item(&mut self, key: &str) -> Option<PluginCacheManifestItem> {
    self.plugins.remove(key)
  }

  fn is_different_schema(&self) -> bool {
    self.schema_version != PLUGIN_CACHE_SCHEMA_VERSION
  }

  fn is_new_wasm_cache(&self) -> bool {
    // bust when upgrading, but not downgrading
    version_gt(&self.wasm_cache_version, WASMER_COMPILER_VERSION)
  }
}

fn version_gt(file: &str, current: &str) -> bool {
  use std::cmp::Ordering;

  for (file, current) in file.split('.').zip(current.split('.')) {
    if let Ok(file) = file.parse::<usize>() {
      if let Ok(current) = current.parse::<usize>() {
        match current.cmp(&file) {
          Ordering::Greater => return true,
          Ordering::Less => return false,
          Ordering::Equal => {
            // keep searching
          }
        }
      }
    }
  }
  false // equal
}

#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PluginCacheManifestItem {
  /// Created time in *seconds* since epoch.
  pub created_
    
  fn should_read_ok_manifest() {
    let environment = TestEnvironment::new();
    environment
      .write_file(
        &environment.get_cache_dir().join("plugin-cache-manifest.json"),
        r#"{
    "schemaVersion": 8,
    "wasmCacheVersion": "99.9.9",
    "plugins": {
        "a": {
            "createdTime": 123,
            "info": {
                "name": "dprint-plugin-typescript",
                "version": "0.1.0",
                "configKey": "typescript",
                "helpUrl": "help url",
                "configSchemaUrl": "schema url"
            }
        },
        "c": {
            "createdTime": 456,
            "fileHash": 10,
            "info": {
                "name": "dprint-plugin-json",
                "version": "0.2.0",
                "configKey": "json",
                "helpUrl": "help url 2",
                "configSchemaUrl": "schema url 2"
            }
        },
        "cargo": {
            "createdTime": 210530,
            "fileHash": 1226,
            "info": {
                "name": "dprint-plugin-cargo",
                "version": "0.2.1",
                "configKey": "cargo",
                "helpUrl": "cargo help url",
                "configSchemaUrl": "cargo schema url",
                "updateUrl": "cargo update url"
            }
        }
    }
}"#,
      )
      .unwrap();

    let mut expected_manifest = PluginCacheManifest::new();
    // should not change a newer version
    expected_manifest.wasm_cache_version = "99.9.9".to_string();
    expected_manifest.add_item(
      String::from("a"),
      PluginCacheManifestItem {
        created_time: 123,
        file_hash: None,
        info: PluginInfo {
          name: "dprint-plugin-typescript".to_string(),
          version: "0.1.0".to_string(),
          config_key: "typescript".to_string(),
          help_url: "help url".to_string(),
          config_schema_url: "schema url".to_string(),
          update_url: None,
        },
      },
    );
    expected_manifest.add_item(
      String::from("c"),
      PluginCacheManifestItem {
        created_time: 456,
        file_hash: Some(10),
        info: PluginInfo {
          name: "dprint-plugin-json".to_string(),
          version: "0.2.0".to_string(),
          config_key: "json".to_string(),
          help_url: "help url 2".to_string(),
          config_schema_url: "schema url 2".to_string(),
          update_url: None,
        },
      },
    );
    expected_manifest.add_item(
      String::from("cargo"),
      PluginCacheManifestItem {
        created_time: 210530,
        file_hash: Some(1226),
        info: PluginInfo {
          name: "dprint-plugin-cargo".to_string(),
          version: "0.2.1".to_string(),
          config_key: "cargo".to_string(),
          help_url: "cargo help url".to_string(),
          config_schema_url: "cargo schema url".to_string(),
          update_url: Some("cargo update url".to_string()),
        },
      },
    );

    assert_eq!(read_manifest(&environment), expected_manifest);
  }