#![warn(missing_docs)]
use std::error::Error;
use std::fmt::{self, Display};
#[cfg(feature = "compat-maybe-const-fn")]
#[deprecated(note = "Should be in a separate crate")]
#[doc(hidden)]
#[macro_export]
macro_rules! maybe_const_fn {
($($x:tt)*) => {
$crate::__impl_maybe_const_fn::maybe_const_fn!($($x)*);
};
}
#[doc(hidden)]
#[cfg(feature = "compat-maybe-const-fn")]
pub extern crate maybe_const_fn as __impl_maybe_const_fn;
mod build;
pub mod date;
pub mod version;
pub use crate::date::Date;
pub use crate::version::{Channel, RustVersion, StableVersionSpec};
pub fn detect_version() -> Result<crate::RustVersion, VersionDetectionError> {
{
let lock = state::state_mutex()
.read()
.unwrap_or_else(std::sync::PoisonError::into_inner);
if let Some(cached) = &*lock {
return Ok(*cached);
}
}
match build::determine_version() {
Ok(success) => {
{
let mut lock = state::state_mutex()
.write()
.unwrap_or_else(std::sync::PoisonError::into_inner);
*lock = Some(success);
}
Ok(success)
}
Err(failure) => Err(failure),
}
}
#[derive(Debug)]
pub struct VersionDetectionError {
desc: String,
cause: Option<std::io::Error>,
}
impl VersionDetectionError {
pub(crate) fn new(desc: String) -> Self {
VersionDetectionError { desc, cause: None }
}
pub(crate) fn with_cause(desc: String, cause: std::io::Error) -> Self {
VersionDetectionError {
desc,
cause: Some(cause),
}
}
}
impl Display for VersionDetectionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.desc)?;
if let Some(ref cause) = self.cause {
write!(f, ": {}", cause)?;
}
Ok(())
}
}
impl Error for VersionDetectionError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.cause.as_ref().map(|x| x as _)
}
}
#[allow(unused_imports)]
mod state {
use std::sync::{Once, RwLock};
#[allow(deprecated)] static CACHED_STATE_INIT: Once = std::sync::ONCE_INIT;
static mut CACHED_STATE: Option<RwLock<Option<crate::RustVersion>>> = None;
pub fn state_mutex() -> &'static RwLock<Option<crate::RustVersion>> {
CACHED_STATE_INIT.call_once(|| {
unsafe {
CACHED_STATE = Some(RwLock::new(None));
}
});
unsafe {
match CACHED_STATE {
Some(ref mutex) => mutex,
None => std::hint::unreachable_unchecked(),
}
}
}
}