Skip to main content

rustpython_vm/
version.rs

1//! Version info constants.
2//!
3//! Most of the constants are auto calculated at compile time. The main exception is the
4//! target CPython version. This is defined and updated in `build.rs`.
5
6macro_rules! parse_consts {
7    ($name: ident, $var: literal) => {
8        pub const $name: usize = match usize::from_str_radix(env!($var), 10) {
9            Ok(v) => v,
10            Err(_) => panic!(concat!("Compile with Cargo to get '", $var, "'")),
11        };
12    };
13}
14
15// CPython target version info
16parse_consts!(MAJOR, "MAJOR_CPY");
17parse_consts!(MINOR, "MINOR_CPY");
18parse_consts!(MICRO, "MICRO_CPY");
19pub const RELEASELEVEL: &str = env!("RELEASE_LEVEL_CPY");
20parse_consts!(RELEASELEVEL_N, "RELEASE_LEVEL_N_CPY");
21parse_consts!(SERIAL, "SERIAL_CPY");
22pub const VERSION_HEX: usize =
23    (MAJOR << 24) | (MINOR << 16) | (MICRO << 8) | (RELEASELEVEL_N << 4) | SERIAL;
24
25#[cfg(windows)]
26pub const WINVER: &str = env!("WINVER_CPY");
27
28pub const GIT_REVISION: &str = env!("RUSTPYTHON_GIT_HASH");
29pub const GIT_IDENTIFIER: &str = env!("RUSTPYTHON_GIT_IDENTIFIER");
30// const GIT_TAG: &str = env!("RUSTPYTHON_GIT_TAG");
31// const GIT_BRANCH: &str = env!("RUSTPYTHON_GIT_BRANCH");
32
33// RustPython version
34parse_consts!(MAJOR_IMPL, "CARGO_PKG_VERSION_MAJOR");
35parse_consts!(MINOR_IMPL, "CARGO_PKG_VERSION_MINOR");
36parse_consts!(MICRO_IMPL, "CARGO_PKG_VERSION_PATCH");
37pub const RELEASELEVEL_IMPL: &str = env!("RUSTPYTHON_RELEASE_LEVEL");
38parse_consts!(RELEASELEVEL_N_IMPL, "RUSTPYTHON_RELEASE_LEVEL_N");
39parse_consts!(SERIAL_IMPL, "RUSTPYTHON_RELEASE_SERIAL");
40pub const VERSION_HEX_IMPL: usize = (MAJOR_IMPL << 24)
41    | (MINOR_IMPL << 16)
42    | (MICRO_IMPL << 8)
43    | (RELEASELEVEL_N_IMPL << 4)
44    | SERIAL_IMPL;
45
46pub const RUSTPYTHON_BUILD_INFO: &str = env!("RUSTPYTHON_BUILD_INFO");
47pub const RUSTPYTHON_VERSION: &str = const {
48    const LEFT: &str = env!("RUSTPYTHON_VERSION_LEFT");
49    const RIGHT: &str = env!("RUSTPYTHON_VERSION_RIGHT");
50    const LEN: usize = LEFT.len() + RIGHT.len() + 1;
51
52    const fn concat() -> [u8; LEN] {
53        let mut bytes_temp = [0u8; LEN];
54
55        let (left, _) = bytes_temp.split_at_mut(LEFT.len());
56        left.copy_from_slice(LEFT.as_bytes());
57        let (_, right) = bytes_temp.split_at_mut(LEFT.len() + 1);
58        right.copy_from_slice(RIGHT.as_bytes());
59        bytes_temp[LEFT.len()] = b'\n';
60
61        bytes_temp
62    }
63
64    const BUF: [u8; LEN] = concat();
65    match str::from_utf8(&BUF) {
66        Ok(v) => v,
67        Err(_) => unreachable!(),
68    }
69};
70
71// Must be aligned to Lib/importlib/_bootstrap_external.py
72// Matches CPython 3.14 (Include/internal/pycore_magic_number.h).
73pub const PYC_MAGIC_NUMBER: u16 = 3627;
74
75// CPython format: magic_number | ('\r' << 16) | ('\n' << 24)
76// This protects against text-mode file reads
77pub const PYC_MAGIC_NUMBER_TOKEN: u32 =
78    (PYC_MAGIC_NUMBER as u32) | ((b'\r' as u32) << 16) | ((b'\n' as u32) << 24);
79
80/// Magic number as little-endian bytes for .pyc files
81pub const PYC_MAGIC_NUMBER_BYTES: [u8; 4] = PYC_MAGIC_NUMBER_TOKEN.to_le_bytes();