repo_description: Empowering everyone to build reliable and efficient software.
repo_topics: compiler language rust
code: use std::path::{Path, PathBuf};
  use std::{fs, str};
  
  use rustc_errors::DiagCtxtHandle;
  use rustc_span::edition::Edition;
  use serde::Serialize;
  
  use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
  
  #[derive(Clone, Debug, Serialize)]
  pub(crate) struct ExternalHtml {
      /// Content that will be included inline in the `<head>` section of a
      /// rendered Markdown file or generated documentation
      pub(crate) in_header: String,
      /// Content that will be included inline between `<body>` and the content of
      /// a rendered Markdown file or generated documentation
      pub(crate) before_content: String,
      /// Content that will be included inline between the content and `</body>` of
      /// a rendered Markdown file or generated documentation
      pub(crate) after_content: String,
  }
  
  impl ExternalHtml {
      pub(crate) fn load(
          in_header: &[String],
          before_content: &[String],
          after_content: &[String],
          md_before_content: &[String],
          md_after_content: &[String],
          nightly_build: bool,
          dcx: DiagCtxtHandle<'_>,
          id_map: &mut IdMap,
          edition: Edition,
          playground: &Option<Playground>,
          loaded_paths: &mut Vec<PathBuf>,
      ) -> Option<ExternalHtml> {
          let codes = ErrorCodes::from(nightly_build);
          let ih = load_external_files(in_header, dcx, loaded_paths)?;
          let bc = {
              let mut bc = load_external_files(before_content, dcx, loaded_paths)?;
              let m_bc = load_external_files(md_before_content, dcx, loaded_paths)?;
              Markdown {
                  content: &m_bc,
                  links: &[],
                  ids: id_map,
                  error_codes: codes,
                  edition,
                  playground,
                  heading_offset: HeadingOffset::H2,
              }
              .write_into(&mut bc)
              .unwrap();
              bc
          };
          let ac = {
              let mut ac = load_external_files(after_content, dcx, loaded_paths)?;
              let m_ac = load_external_files(md_after_content, dcx, loaded_paths)?;
              Markdown {
                  content: &m_ac,
                  links: &[],
                  ids: id_map,
                  error_codes: codes,
                  edition,
                  playground,
                  heading_offset: HeadingOffset::H2,
              }
              .write_into(&mut ac)
              .unwrap();
              ac
          };
          Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
      }
  }
  
  pub(crate) enum LoadStringError {
      ReadFail,
      BadUtf8,
  }
  
  pub(crate) fn load_string<P: AsRef<Path>>(
      file_path: P,
      dcx: DiagCtxtHandle<'_>,
      loaded_paths: &mut Vec<PathBuf>,
  ) -> Result<String, LoadStringError> {
      let file_path = file_path.as_ref();
      loaded_paths.push(file_path.to_owned());
      let contents = match fs::read(file_path) {
          Ok(bytes) => bytes,
          Err(e) => {
              dcx.struct_err(format!(
                  "error reading `{file_path}`: {e}",
                  file_path = file_path.display()
              ))
              .emit();
              return Err(LoadStringError::ReadFail);
          }
      };
      match str::from_utf8(&contents) {
          Ok(s) => Ok(s.to_string()),
          Err(_) => {
              dcx.err(format!("error reading `{}`: not UTF-8", file_path.display()));
              Err(LoadStringError::BadUtf8)
          }
      }
  }
  
  fn load_external_files(
      names: &[String],
      dcx: DiagCtxtHandle<'_>,
      loaded_paths: &mut Vec<PathBuf>,
  ) -> Option<String> {
      let mut out = String::new();
      for name in names {
          let Ok(s) = load_string(name, dcx, loaded_paths) else { return None };
          out.push_str(&s);
          out.push('\n');
      }
      Some(out)
  }
  