rustpython_vm/function/
doctext.rs1#[cfg(feature = "doc")]
6use std::sync::OnceLock;
7
8#[derive(Clone, Copy, Debug)]
13pub struct ItemDoc {
14 pub text: Option<&'static str>,
15 pub offset: u32,
16 pub len: u32,
17}
18
19impl ItemDoc {
20 pub const NONE: Self = Self {
21 text: None,
22 offset: 0,
23 len: 0,
24 };
25
26 pub const EMPTY: Self = Self {
29 text: None,
30 offset: u32::MAX,
31 len: 0,
32 };
33
34 #[must_use]
35 pub const fn static_text(text: &'static str) -> Self {
36 Self {
37 text: Some(text),
38 offset: 0,
39 len: 0,
40 }
41 }
42
43 #[must_use]
44 pub const fn is_db(self) -> bool {
45 self.len != 0
46 }
47
48 #[must_use]
51 pub const fn db(key: &str) -> Self {
52 #[cfg(feature = "doc")]
53 if let Some(doc) = rustpython_doc::get(key) {
54 return Self {
55 text: None,
56 offset: doc.offset,
57 len: doc.len,
58 };
59 }
60 #[cfg(not(feature = "doc"))]
61 let _ = key;
62 Self::NONE
63 }
64}
65
66impl Default for ItemDoc {
67 fn default() -> Self {
68 Self::NONE
69 }
70}
71
72#[inline(never)]
73#[must_use]
74pub fn db_doc(offset: u32, len: u32) -> Option<&'static str> {
75 if len == 0 {
76 return None;
77 }
78 db_slice(offset, len)
79}
80
81#[inline(never)]
82#[must_use]
83pub fn plain_doc(doc: ItemDoc) -> Option<&'static str> {
84 if doc.offset == u32::MAX && doc.len == 0 {
85 return Some("");
86 }
87 if doc.len != 0 {
88 return db_doc(doc.offset, doc.len);
89 }
90 doc.text.filter(|text| !text.is_empty())
91}
92
93#[cfg(feature = "doc")]
94#[inline(never)]
95fn db_slice(offset: u32, len: u32) -> Option<&'static str> {
96 let text = docs();
97 let start = offset as usize;
98 let end = start.checked_add(len as usize)?;
99 text.get(start..end)
100}
101
102#[cfg(not(feature = "doc"))]
103fn db_slice(_offset: u32, _len: u32) -> Option<&'static str> {
104 None
105}
106
107#[cfg(feature = "doc")]
108#[inline(never)]
109fn docs() -> &'static str {
110 static TEXT: OnceLock<Box<str>> = OnceLock::new();
111 TEXT.get_or_init(|| {
112 let bytes = match xz::decode_all(rustpython_doc::BLOB) {
113 Ok(bytes) => bytes,
114 Err(_) => panic!("doc blob"),
115 };
116 match String::from_utf8(bytes) {
117 Ok(text) => text.into_boxed_str(),
118 Err(_) => panic!("doc blob"),
119 }
120 })
121 .as_ref()
122}
123
124#[cfg(test)]
125mod tests {
126 use super::{ItemDoc, plain_doc};
127
128 #[test]
129 fn explicit_empty_doc_is_empty_string() {
130 assert_eq!(plain_doc(ItemDoc::EMPTY), Some(""));
131 assert_eq!(plain_doc(ItemDoc::NONE), None);
132 assert_eq!(plain_doc(ItemDoc::static_text("")), None);
133 assert_eq!(plain_doc(ItemDoc::static_text("a")), Some("a"));
134 }
135}