LCOV - code coverage report
Current view: top level - internal/src - config.rs (source / functions) Hit Total Coverage
Test: unnamed Lines: 35 53 66.0 %
Date: 2024-10-23 19:20:50 Functions: 3 11 27.3 %

          Line data    Source code
       1             : use std::{fs::read_to_string, sync::OnceLock};
       2             : use thiserror::Error as ThisError;
       3             : 
       4             : pub type Result<T> = std::result::Result<T, Error>;
       5             : 
       6             : #[derive(Debug, ThisError)]
       7             : pub struct Error {
       8             :     inner: Inner,
       9             : }
      10             : 
      11             : impl Error {
      12             :     #[must_use]
      13           0 :     pub const fn other(value: String) -> Self {
      14           0 :         Self {
      15           0 :             inner: Inner::Other(value),
      16           0 :         }
      17           0 :     }
      18             : }
      19             : 
      20             : impl std::fmt::Display for Error {
      21           0 :     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
      22           0 :         write!(f, "{}", self.inner)
      23           0 :     }
      24             : }
      25             : 
      26             : impl<T> From<T> for Error
      27             : where
      28             :     Inner: From<T>,
      29             : {
      30           0 :     fn from(value: T) -> Self {
      31           0 :         Self {
      32           0 :             inner: Inner::from(value),
      33           0 :         }
      34           0 :     }
      35             : }
      36             : 
      37             : #[derive(Debug, ThisError)]
      38             : enum Inner {
      39             :     #[error("cargo metadata error: {0}")]
      40             :     CargoMetadata(#[from] cargo_metadata::Error),
      41             :     #[error("io error: {0}: {1}")]
      42             :     Io(String, std::io::Error),
      43             :     #[error("toml error: {0}")]
      44             :     Toml(#[from] toml::de::Error),
      45             :     #[error("{0}")]
      46             :     Other(String),
      47             : }
      48             : 
      49             : static CONFIG_TABLE: OnceLock<toml::value::Table> = OnceLock::new();
      50             : 
      51          24 : pub fn get() -> Option<&'static toml::value::Table> {
      52          24 :     CONFIG_TABLE.get()
      53          24 : }
      54             : 
      55             : // smoelius: `try_init_with_metadata` returns a string so that `dylint_linting` can record it in
      56             : // `file_depinfo`.
      57          24 : pub fn try_init_with_metadata(metadata: &cargo_metadata::Metadata) -> Result<Option<String>> {
      58          24 :     if CONFIG_TABLE.get().is_some() {
      59           0 :         return Ok(None);
      60          24 :     }
      61          24 : 
      62          24 :     let cargo_metadata::Metadata { workspace_root, .. } = metadata;
      63          24 : 
      64          24 :     let dylint_toml = workspace_root.join("dylint.toml");
      65             : 
      66          24 :     let value = if dylint_toml
      67          24 :         .try_exists()
      68          24 :         .map_err(|error| Inner::Io(format!("`try_exists` failed for {dylint_toml:?}"), error))?
      69             :     {
      70           1 :         let value = read_to_string(&dylint_toml).map_err(|error| {
      71           0 :             Inner::Io(
      72           0 :                 format!("`read_to_string` failed for {dylint_toml:?}"),
      73           0 :                 error,
      74           0 :             )
      75           1 :         })?;
      76           1 :         Some(value)
      77             :     } else {
      78          23 :         None
      79             :     };
      80             : 
      81          24 :     if let Some(s) = &value {
      82           1 :         init_from_string(s)?;
      83          23 :     }
      84             : 
      85          24 :     Ok(value)
      86          24 : }
      87             : 
      88           1 : pub fn init_from_string(s: &str) -> Result<()> {
      89           1 :     assert!(CONFIG_TABLE.get().is_none());
      90             : 
      91           1 :     let toml: toml::Value = toml::from_str(s)?;
      92             : 
      93           1 :     let table = toml
      94           1 :         .as_table()
      95           1 :         .cloned()
      96           1 :         .ok_or_else(|| Inner::Other("Value is not a table".into()))?;
      97             : 
      98             :     // smoelius: Rewrite this function (`init_from_string`) and eliminate the next `expect` once
      99             :     // `get_or_try_init` stabilizes: https://github.com/rust-lang/rust/issues/109737
     100           1 :     CONFIG_TABLE
     101           1 :         .set(table)
     102           1 :         .expect("`CONFIG_TABLE` was determined to be unset above");
     103           1 : 
     104           1 :     Ok(())
     105           1 : }

Generated by: LCOV version 1.14