rustversion_detect/
lib.rs1#![deny(missing_docs)]
18use std::error::Error;
19use std::fmt::{self, Display};
20
21#[macro_use]
22mod macros;
23mod build;
24pub mod date;
25pub mod version;
26
27pub use crate::date::Date;
28pub use crate::version::{Channel, RustVersion, StableVersionSpec};
29
30pub fn detect_version() -> Result<crate::RustVersion, VersionDetectionError> {
44 {
45 let lock = state::state_mutex()
46 .read()
47 .unwrap_or_else(std::sync::PoisonError::into_inner);
48 match &*lock {
49 Some(cached) => return Ok(*cached),
50 _ => {
51 }
53 }
54 }
55 match build::determine_version() {
56 Ok(success) => {
57 {
58 let mut lock = state::state_mutex()
59 .write()
60 .unwrap_or_else(std::sync::PoisonError::into_inner);
61 *lock = Some(success);
62 }
63 Ok(success)
64 }
65 Err(failure) => Err(failure),
66 }
67}
68
69#[derive(Debug)]
71pub struct VersionDetectionError {
72 desc: String,
73 cause: Option<std::io::Error>,
74}
75impl VersionDetectionError {
76 pub(crate) fn new(desc: String) -> Self {
77 VersionDetectionError { desc, cause: None }
78 }
79
80 pub(crate) fn with_cause(desc: String, cause: std::io::Error) -> Self {
81 VersionDetectionError {
82 desc,
83 cause: Some(cause),
84 }
85 }
86}
87impl Display for VersionDetectionError {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 write!(f, "{}", self.desc)?;
90 if let Some(ref cause) = self.cause {
91 write!(f, ": {}", cause)?;
92 }
93 Ok(())
94 }
95}
96impl Error for VersionDetectionError {
97 fn source(&self) -> Option<&(dyn Error + 'static)> {
98 self.cause.as_ref().map(|x| x as _)
99 }
100}
101
102#[allow(unused_imports)]
104mod state {
105 use std::sync::{Once, RwLock};
106
107 #[allow(deprecated)] static CACHED_STATE_INIT: Once = std::sync::ONCE_INIT;
109 static mut CACHED_STATE: Option<RwLock<Option<crate::RustVersion>>> = None;
110
111 pub fn state_mutex() -> &'static RwLock<Option<crate::RustVersion>> {
112 CACHED_STATE_INIT.call_once(|| {
113 unsafe {
115 CACHED_STATE = Some(RwLock::new(None));
116 }
117 });
118 unsafe {
121 match CACHED_STATE {
122 Some(ref mutex) => mutex,
123 None => std::hint::unreachable_unchecked(),
124 }
125 }
126 }
127}