| 1 | // Copyright 2016 rustc-version-rs developers | 
| 2 | // | 
|---|
| 3 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | 
|---|
| 4 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | 
|---|
| 5 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | 
|---|
| 6 | // option. This file may not be copied, modified, or distributed | 
|---|
| 7 | // except according to those terms. | 
|---|
| 8 |  | 
|---|
| 9 | #![ warn(missing_docs)] | 
|---|
| 10 |  | 
|---|
| 11 | //! Simple library for getting the version information of a `rustc` | 
|---|
| 12 | //! compiler. | 
|---|
| 13 | //! | 
|---|
| 14 | //! This can be used by build scripts or other tools dealing with Rust sources | 
|---|
| 15 | //! to make decisions based on the version of the compiler. | 
|---|
| 16 | //! | 
|---|
| 17 | //! It calls `$RUSTC --version -v` and parses the output, falling | 
|---|
| 18 | //! back to `rustc` if `$RUSTC` is not set. | 
|---|
| 19 | //! | 
|---|
| 20 | //! # Example | 
|---|
| 21 | //! | 
|---|
| 22 | //! ```rust | 
|---|
| 23 | //! // This could be a cargo build script | 
|---|
| 24 | //! | 
|---|
| 25 | //! use rustc_version::{version, version_meta, Channel, Version}; | 
|---|
| 26 | //! | 
|---|
| 27 | //! // Assert we haven't travelled back in time | 
|---|
| 28 | //! assert!(version().unwrap().major >= 1); | 
|---|
| 29 | //! | 
|---|
| 30 | //! // Set cfg flags depending on release channel | 
|---|
| 31 | //! match version_meta().unwrap().channel { | 
|---|
| 32 | //!     Channel::Stable => { | 
|---|
| 33 | //!         println!( "cargo:rustc-cfg=RUSTC_IS_STABLE"); | 
|---|
| 34 | //!     } | 
|---|
| 35 | //!     Channel::Beta => { | 
|---|
| 36 | //!         println!( "cargo:rustc-cfg=RUSTC_IS_BETA"); | 
|---|
| 37 | //!     } | 
|---|
| 38 | //!     Channel::Nightly => { | 
|---|
| 39 | //!         println!( "cargo:rustc-cfg=RUSTC_IS_NIGHTLY"); | 
|---|
| 40 | //!     } | 
|---|
| 41 | //!     Channel::Dev => { | 
|---|
| 42 | //!         println!( "cargo:rustc-cfg=RUSTC_IS_DEV"); | 
|---|
| 43 | //!     } | 
|---|
| 44 | //! } | 
|---|
| 45 | //! | 
|---|
| 46 | //! // Check for a minimum version | 
|---|
| 47 | //! if version().unwrap() >= Version::parse( "1.4.0").unwrap() { | 
|---|
| 48 | //!     println!( "cargo:rustc-cfg=compiler_has_important_bugfix"); | 
|---|
| 49 | //! } | 
|---|
| 50 | //! ``` | 
|---|
| 51 |  | 
|---|
| 52 | #[ cfg(test)] | 
|---|
| 53 | #[ macro_use] | 
|---|
| 54 | extern crate doc_comment; | 
|---|
| 55 |  | 
|---|
| 56 | #[ cfg(test)] | 
|---|
| 57 | doctest!( "../README.md"); | 
|---|
| 58 |  | 
|---|
| 59 | use std::collections::HashMap; | 
|---|
| 60 | use std::process::Command; | 
|---|
| 61 | use std::{env, error, fmt, io, num, str}; | 
|---|
| 62 | use std::{ffi::OsString, str::FromStr}; | 
|---|
| 63 |  | 
|---|
| 64 | // Convenience re-export to allow version comparison without needing to add | 
|---|
| 65 | // semver crate. | 
|---|
| 66 | pub use semver::Version; | 
|---|
| 67 |  | 
|---|
| 68 | use Error::*; | 
|---|
| 69 |  | 
|---|
| 70 | /// Release channel of the compiler. | 
|---|
| 71 | #[ derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] | 
|---|
| 72 | pub enum Channel { | 
|---|
| 73 | /// Development release channel | 
|---|
| 74 | Dev, | 
|---|
| 75 | /// Nightly release channel | 
|---|
| 76 | Nightly, | 
|---|
| 77 | /// Beta release channel | 
|---|
| 78 | Beta, | 
|---|
| 79 | /// Stable release channel | 
|---|
| 80 | Stable, | 
|---|
| 81 | } | 
|---|
| 82 |  | 
|---|
| 83 | /// LLVM version | 
|---|
| 84 | /// | 
|---|
| 85 | /// LLVM's version numbering scheme is not semver compatible until version 4.0 | 
|---|
| 86 | /// | 
|---|
| 87 | /// rustc [just prints the major and minor versions], so other parts of the version are not included. | 
|---|
| 88 | /// | 
|---|
| 89 | /// [just prints the major and minor versions]: https://github.com/rust-lang/rust/blob/b5c9e2448c9ace53ad5c11585803894651b18b0a/compiler/rustc_codegen_llvm/src/llvm_util.rs#L173-L178 | 
|---|
| 90 | #[ derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] | 
|---|
| 91 | pub struct LlvmVersion { | 
|---|
| 92 | // fields must be ordered major, minor for comparison to be correct | 
|---|
| 93 | /// Major version | 
|---|
| 94 | pub major: u64, | 
|---|
| 95 | /// Minor version | 
|---|
| 96 | pub minor: u64, | 
|---|
| 97 | // TODO: expose micro version here | 
|---|
| 98 | } | 
|---|
| 99 |  | 
|---|
| 100 | impl fmt::Display for LlvmVersion { | 
|---|
| 101 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|---|
| 102 | write!(f, "{} .{} ", self.major, self.minor) | 
|---|
| 103 | } | 
|---|
| 104 | } | 
|---|
| 105 |  | 
|---|
| 106 | impl FromStr for LlvmVersion { | 
|---|
| 107 | type Err = LlvmVersionParseError; | 
|---|
| 108 |  | 
|---|
| 109 | fn from_str(s: &str) -> Result<Self, Self::Err> { | 
|---|
| 110 | let mut parts = s | 
|---|
| 111 | .split( '.') | 
|---|
| 112 | .map(|part| -> Result<u64, LlvmVersionParseError> { | 
|---|
| 113 | if part == "0"{ | 
|---|
| 114 | Ok(0) | 
|---|
| 115 | } else if part.starts_with( '0') { | 
|---|
| 116 | Err(LlvmVersionParseError::ComponentMustNotHaveLeadingZeros) | 
|---|
| 117 | } else if part.starts_with( '-') || part.starts_with( '+') { | 
|---|
| 118 | Err(LlvmVersionParseError::ComponentMustNotHaveSign) | 
|---|
| 119 | } else { | 
|---|
| 120 | Ok(part.parse()?) | 
|---|
| 121 | } | 
|---|
| 122 | }); | 
|---|
| 123 |  | 
|---|
| 124 | let major = parts.next().unwrap()?; | 
|---|
| 125 | let mut minor = 0; | 
|---|
| 126 |  | 
|---|
| 127 | if let Some(part) = parts.next() { | 
|---|
| 128 | minor = part?; | 
|---|
| 129 | } else if major < 4 { | 
|---|
| 130 | // LLVM versions earlier than 4.0 have significant minor versions, so require the minor version in this case. | 
|---|
| 131 | return Err(LlvmVersionParseError::MinorVersionRequiredBefore4); | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | if let Some(Err(e)) = parts.next() { | 
|---|
| 135 | return Err(e); | 
|---|
| 136 | } | 
|---|
| 137 |  | 
|---|
| 138 | if parts.next().is_some() { | 
|---|
| 139 | return Err(LlvmVersionParseError::TooManyComponents); | 
|---|
| 140 | } | 
|---|
| 141 |  | 
|---|
| 142 | Ok(Self { major, minor }) | 
|---|
| 143 | } | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | /// Rustc version plus metadata like git short hash and build date. | 
|---|
| 147 | #[ derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] | 
|---|
| 148 | pub struct VersionMeta { | 
|---|
| 149 | /// Version of the compiler | 
|---|
| 150 | pub semver: Version, | 
|---|
| 151 |  | 
|---|
| 152 | /// Git short hash of the build of the compiler | 
|---|
| 153 | pub commit_hash: Option<String>, | 
|---|
| 154 |  | 
|---|
| 155 | /// Commit date of the compiler | 
|---|
| 156 | pub commit_date: Option<String>, | 
|---|
| 157 |  | 
|---|
| 158 | /// Build date of the compiler; this was removed between Rust 1.0.0 and 1.1.0. | 
|---|
| 159 | pub build_date: Option<String>, | 
|---|
| 160 |  | 
|---|
| 161 | /// Release channel of the compiler | 
|---|
| 162 | pub channel: Channel, | 
|---|
| 163 |  | 
|---|
| 164 | /// Host target triple of the compiler | 
|---|
| 165 | pub host: String, | 
|---|
| 166 |  | 
|---|
| 167 | /// Short version string of the compiler | 
|---|
| 168 | pub short_version_string: String, | 
|---|
| 169 |  | 
|---|
| 170 | /// Version of LLVM used by the compiler | 
|---|
| 171 | pub llvm_version: Option<LlvmVersion>, | 
|---|
| 172 | } | 
|---|
| 173 |  | 
|---|
| 174 | impl VersionMeta { | 
|---|
| 175 | /// Returns the version metadata for `cmd`, which should be a `rustc` command. | 
|---|
| 176 | pub fn for_command(mut cmd: Command) -> Result<VersionMeta> { | 
|---|
| 177 | let out: Output = cmd | 
|---|
| 178 | .arg( "-vV") | 
|---|
| 179 | .output() | 
|---|
| 180 | .map_err(op:Error::CouldNotExecuteCommand)?; | 
|---|
| 181 |  | 
|---|
| 182 | if !out.status.success() { | 
|---|
| 183 | return Err(Error::CommandError { | 
|---|
| 184 | stdout: String::from_utf8_lossy(&out.stdout).into(), | 
|---|
| 185 | stderr: String::from_utf8_lossy(&out.stderr).into(), | 
|---|
| 186 | }); | 
|---|
| 187 | } | 
|---|
| 188 |  | 
|---|
| 189 | version_meta_for(verbose_version_string:str::from_utf8(&out.stdout)?) | 
|---|
| 190 | } | 
|---|
| 191 | } | 
|---|
| 192 |  | 
|---|
| 193 | /// Returns the `rustc` SemVer version. | 
|---|
| 194 | pub fn version() -> Result<Version> { | 
|---|
| 195 | Ok(version_meta()?.semver) | 
|---|
| 196 | } | 
|---|
| 197 |  | 
|---|
| 198 | /// Returns the `rustc` SemVer version and additional metadata | 
|---|
| 199 | /// like the git short hash and build date. | 
|---|
| 200 | pub fn version_meta() -> Result<VersionMeta> { | 
|---|
| 201 | let rustc: OsString = env::var_os(key: "RUSTC").unwrap_or_else(|| OsString::from( "rustc")); | 
|---|
| 202 | let cmd: Command = if let Some(wrapper: OsString) = env::var_os(key: "RUSTC_WRAPPER").filter(|w: &OsString| !w.is_empty()) { | 
|---|
| 203 | let mut cmd: Command = Command::new(program:wrapper); | 
|---|
| 204 | cmd.arg(rustc); | 
|---|
| 205 | cmd | 
|---|
| 206 | } else { | 
|---|
| 207 | Command::new(program:rustc) | 
|---|
| 208 | }; | 
|---|
| 209 |  | 
|---|
| 210 | VersionMeta::for_command(cmd) | 
|---|
| 211 | } | 
|---|
| 212 |  | 
|---|
| 213 | /// Parses a "rustc -vV" output string and returns | 
|---|
| 214 | /// the SemVer version and additional metadata | 
|---|
| 215 | /// like the git short hash and build date. | 
|---|
| 216 | pub fn version_meta_for(verbose_version_string: &str) -> Result<VersionMeta> { | 
|---|
| 217 | let mut map = HashMap::new(); | 
|---|
| 218 | for (i, line) in verbose_version_string.lines().enumerate() { | 
|---|
| 219 | if i == 0 { | 
|---|
| 220 | map.insert( "short", line); | 
|---|
| 221 | continue; | 
|---|
| 222 | } | 
|---|
| 223 |  | 
|---|
| 224 | let mut parts = line.splitn(2, ": "); | 
|---|
| 225 | let key = match parts.next() { | 
|---|
| 226 | Some(key) => key, | 
|---|
| 227 | None => continue, | 
|---|
| 228 | }; | 
|---|
| 229 |  | 
|---|
| 230 | if let Some(value) = parts.next() { | 
|---|
| 231 | map.insert(key, value); | 
|---|
| 232 | } | 
|---|
| 233 | } | 
|---|
| 234 |  | 
|---|
| 235 | let short_version_string = expect_key( "short", &map)?; | 
|---|
| 236 | let host = expect_key( "host", &map)?; | 
|---|
| 237 | let release = expect_key( "release", &map)?; | 
|---|
| 238 | let semver: Version = release.parse()?; | 
|---|
| 239 |  | 
|---|
| 240 | let channel = match semver.pre.split( '.').next().unwrap() { | 
|---|
| 241 | ""=> Channel::Stable, | 
|---|
| 242 | "dev"=> Channel::Dev, | 
|---|
| 243 | "beta"=> Channel::Beta, | 
|---|
| 244 | "nightly"=> Channel::Nightly, | 
|---|
| 245 | x => return Err(Error::UnknownPreReleaseTag(x.to_owned())), | 
|---|
| 246 | }; | 
|---|
| 247 |  | 
|---|
| 248 | let commit_hash = expect_key_or_unknown( "commit-hash", &map)?; | 
|---|
| 249 | let commit_date = expect_key_or_unknown( "commit-date", &map)?; | 
|---|
| 250 | let build_date = map | 
|---|
| 251 | .get( "build-date") | 
|---|
| 252 | .filter(|&v| *v != "unknown") | 
|---|
| 253 | .map(|&v| String::from(v)); | 
|---|
| 254 | let llvm_version = match map.get( "LLVM version") { | 
|---|
| 255 | Some(&v) => Some(v.parse()?), | 
|---|
| 256 | None => None, | 
|---|
| 257 | }; | 
|---|
| 258 |  | 
|---|
| 259 | Ok(VersionMeta { | 
|---|
| 260 | semver, | 
|---|
| 261 | commit_hash, | 
|---|
| 262 | commit_date, | 
|---|
| 263 | build_date, | 
|---|
| 264 | channel, | 
|---|
| 265 | host, | 
|---|
| 266 | short_version_string, | 
|---|
| 267 | llvm_version, | 
|---|
| 268 | }) | 
|---|
| 269 | } | 
|---|
| 270 |  | 
|---|
| 271 | fn expect_key_or_unknown(key: &str, map: &HashMap<&str, &str>) -> Result<Option<String>, Error> { | 
|---|
| 272 | match map.get(key) { | 
|---|
| 273 | Some(& "unknown") => Ok(None), | 
|---|
| 274 | Some(&v: &str) => Ok(Some(String::from(v))), | 
|---|
| 275 | None => Err(Error::UnexpectedVersionFormat), | 
|---|
| 276 | } | 
|---|
| 277 | } | 
|---|
| 278 |  | 
|---|
| 279 | fn expect_key(key: &str, map: &HashMap<&str, &str>) -> Result<String, Error> { | 
|---|
| 280 | map.get(key) | 
|---|
| 281 | .map(|&v| String::from(v)) | 
|---|
| 282 | .ok_or(err:Error::UnexpectedVersionFormat) | 
|---|
| 283 | } | 
|---|
| 284 |  | 
|---|
| 285 | /// LLVM Version Parse Error | 
|---|
| 286 | #[ derive(Debug)] | 
|---|
| 287 | pub enum LlvmVersionParseError { | 
|---|
| 288 | /// An error occurred in parsing a version component as an integer | 
|---|
| 289 | ParseIntError(num::ParseIntError), | 
|---|
| 290 | /// A version component must not have leading zeros | 
|---|
| 291 | ComponentMustNotHaveLeadingZeros, | 
|---|
| 292 | /// A version component has a sign | 
|---|
| 293 | ComponentMustNotHaveSign, | 
|---|
| 294 | /// Minor version component must be zero on LLVM versions later than 4.0 | 
|---|
| 295 | MinorVersionMustBeZeroAfter4, | 
|---|
| 296 | /// Minor version component is required on LLVM versions earlier than 4.0 | 
|---|
| 297 | MinorVersionRequiredBefore4, | 
|---|
| 298 | /// Too many components | 
|---|
| 299 | TooManyComponents, | 
|---|
| 300 | } | 
|---|
| 301 |  | 
|---|
| 302 | impl From<num::ParseIntError> for LlvmVersionParseError { | 
|---|
| 303 | fn from(e: num::ParseIntError) -> Self { | 
|---|
| 304 | LlvmVersionParseError::ParseIntError(e) | 
|---|
| 305 | } | 
|---|
| 306 | } | 
|---|
| 307 |  | 
|---|
| 308 | impl fmt::Display for LlvmVersionParseError { | 
|---|
| 309 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|---|
| 310 | match self { | 
|---|
| 311 | LlvmVersionParseError::ParseIntError(e: &ParseIntError) => { | 
|---|
| 312 | write!(f, "error parsing LLVM version component: {} ", e) | 
|---|
| 313 | } | 
|---|
| 314 | LlvmVersionParseError::ComponentMustNotHaveLeadingZeros => { | 
|---|
| 315 | write!(f, "a version component must not have leading zeros") | 
|---|
| 316 | } | 
|---|
| 317 | LlvmVersionParseError::ComponentMustNotHaveSign => { | 
|---|
| 318 | write!(f, "a version component must not have a sign") | 
|---|
| 319 | } | 
|---|
| 320 | LlvmVersionParseError::MinorVersionMustBeZeroAfter4 => write!( | 
|---|
| 321 | f, | 
|---|
| 322 | "LLVM's minor version component must be 0 for versions greater than 4.0" | 
|---|
| 323 | ), | 
|---|
| 324 | LlvmVersionParseError::MinorVersionRequiredBefore4 => write!( | 
|---|
| 325 | f, | 
|---|
| 326 | "LLVM's minor version component is required for versions less than 4.0" | 
|---|
| 327 | ), | 
|---|
| 328 | LlvmVersionParseError::TooManyComponents => write!(f, "too many version components"), | 
|---|
| 329 | } | 
|---|
| 330 | } | 
|---|
| 331 | } | 
|---|
| 332 |  | 
|---|
| 333 | impl error::Error for LlvmVersionParseError { | 
|---|
| 334 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { | 
|---|
| 335 | match self { | 
|---|
| 336 | LlvmVersionParseError::ParseIntError(e: &ParseIntError) => Some(e), | 
|---|
| 337 | LlvmVersionParseError::ComponentMustNotHaveLeadingZeros | 
|---|
| 338 | | LlvmVersionParseError::ComponentMustNotHaveSign | 
|---|
| 339 | | LlvmVersionParseError::MinorVersionMustBeZeroAfter4 | 
|---|
| 340 | | LlvmVersionParseError::MinorVersionRequiredBefore4 | 
|---|
| 341 | | LlvmVersionParseError::TooManyComponents => None, | 
|---|
| 342 | } | 
|---|
| 343 | } | 
|---|
| 344 | } | 
|---|
| 345 |  | 
|---|
| 346 | /// The error type for this crate. | 
|---|
| 347 | #[ derive(Debug)] | 
|---|
| 348 | pub enum Error { | 
|---|
| 349 | /// An error occurred while trying to find the `rustc` to run. | 
|---|
| 350 | CouldNotExecuteCommand(io::Error), | 
|---|
| 351 | /// Error output from the command that was run. | 
|---|
| 352 | CommandError { | 
|---|
| 353 | /// stdout output from the command | 
|---|
| 354 | stdout: String, | 
|---|
| 355 | /// stderr output from the command | 
|---|
| 356 | stderr: String, | 
|---|
| 357 | }, | 
|---|
| 358 | /// The output of `rustc -vV` was not valid utf-8. | 
|---|
| 359 | Utf8Error(str::Utf8Error), | 
|---|
| 360 | /// The output of `rustc -vV` was not in the expected format. | 
|---|
| 361 | UnexpectedVersionFormat, | 
|---|
| 362 | /// An error occurred in parsing the semver. | 
|---|
| 363 | SemVerError(semver::Error), | 
|---|
| 364 | /// The pre-release tag is unknown. | 
|---|
| 365 | UnknownPreReleaseTag(String), | 
|---|
| 366 | /// An error occurred in parsing a `LlvmVersion`. | 
|---|
| 367 | LlvmVersionError(LlvmVersionParseError), | 
|---|
| 368 | } | 
|---|
| 369 |  | 
|---|
| 370 | impl fmt::Display for Error { | 
|---|
| 371 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|---|
| 372 | match *self { | 
|---|
| 373 | CouldNotExecuteCommand(ref e: &Error) => write!(f, "could not execute command: {} ", e), | 
|---|
| 374 | CommandError { | 
|---|
| 375 | ref stdout: &String, | 
|---|
| 376 | ref stderr: &String, | 
|---|
| 377 | } => write!( | 
|---|
| 378 | f, | 
|---|
| 379 | "error from command -- stderr:\n\n{}\n\n stderr:\n\n{} ", | 
|---|
| 380 | stderr, stdout, | 
|---|
| 381 | ), | 
|---|
| 382 | Utf8Error(_) => write!(f, "invalid UTF-8 output from `rustc -vV`"), | 
|---|
| 383 | UnexpectedVersionFormat => write!(f, "unexpected `rustc -vV` format"), | 
|---|
| 384 | SemVerError(ref e: &Error) => write!(f, "error parsing version: {} ", e), | 
|---|
| 385 | UnknownPreReleaseTag(ref i: &String) => write!(f, "unknown pre-release tag: {} ", i), | 
|---|
| 386 | LlvmVersionError(ref e: &LlvmVersionParseError) => write!(f, "error parsing LLVM's version: {} ", e), | 
|---|
| 387 | } | 
|---|
| 388 | } | 
|---|
| 389 | } | 
|---|
| 390 |  | 
|---|
| 391 | impl error::Error for Error { | 
|---|
| 392 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { | 
|---|
| 393 | match *self { | 
|---|
| 394 | CouldNotExecuteCommand(ref e: &Error) => Some(e), | 
|---|
| 395 | CommandError { .. } => None, | 
|---|
| 396 | Utf8Error(ref e: &Utf8Error) => Some(e), | 
|---|
| 397 | UnexpectedVersionFormat => None, | 
|---|
| 398 | SemVerError(ref e: &Error) => Some(e), | 
|---|
| 399 | UnknownPreReleaseTag(_) => None, | 
|---|
| 400 | LlvmVersionError(ref e: &LlvmVersionParseError) => Some(e), | 
|---|
| 401 | } | 
|---|
| 402 | } | 
|---|
| 403 | } | 
|---|
| 404 |  | 
|---|
| 405 | macro_rules! impl_from { | 
|---|
| 406 | ($($err_ty:ty => $variant:ident),* $(,)*) => { | 
|---|
| 407 | $( | 
|---|
| 408 | impl From<$err_ty> for Error { | 
|---|
| 409 | fn from(e: $err_ty) -> Error { | 
|---|
| 410 | Error::$variant(e) | 
|---|
| 411 | } | 
|---|
| 412 | } | 
|---|
| 413 | )* | 
|---|
| 414 | } | 
|---|
| 415 | } | 
|---|
| 416 |  | 
|---|
| 417 | impl_from! { | 
|---|
| 418 | str::Utf8Error => Utf8Error, | 
|---|
| 419 | semver::Error => SemVerError, | 
|---|
| 420 | LlvmVersionParseError => LlvmVersionError, | 
|---|
| 421 | } | 
|---|
| 422 |  | 
|---|
| 423 | /// The result type for this crate. | 
|---|
| 424 | pub type Result<T, E = Error> = std::result::Result<T, E>; | 
|---|
| 425 |  | 
|---|