1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use crate::generator::features::Features0;
use crate::generator::names::Names;
use crate::generator::Derive;
use crate::parser::feature::FeatureParser;
use proc_macro2::TokenStream;
use quote::quote;
use syn::Visibility;
pub(crate) struct FeatureNextBackFn {
pub(crate) enabled: bool,
pub(crate) vis: Option<Visibility>,
pub(crate) name: String,
}
impl FeatureNextBackFn {
pub(crate) fn parse(feature_parser: &mut FeatureParser) -> Self {
if let Some(mut params) = feature_parser.get("next_back") {
let (vis, name) = params.get_vis_name("next_back");
params.finish(Self {
enabled: true,
vis,
name,
})
} else {
Self {
enabled: false,
vis: Some(Visibility::Inherited),
name: "__next_back".to_string(),
}
}
}
pub(crate) fn check(&self, features: &mut Features0) {
if !self.enabled {
return;
}
features.min_const.enabled = true;
// range_table is only created when in with holes mode
features.table_range.enabled = true;
}
pub(crate) fn generate(self, derive: &Derive, names: &Names) -> TokenStream {
if !self.enabled {
return TokenStream::new();
}
let Derive { repr, .. } = derive;
let Names {
ident_min,
ident_next_back,
ident_table_range,
..
} = names;
let vis = self.vis.as_ref().unwrap_or(&derive.vis_enum);
if derive.mode.is_gapless() {
quote! {
/// Returns the previous element before this in value order
#[inline]
#vis fn #ident_next_back(self) -> ::core::option::Option<Self> {
use ::core::option::Option::{None, Some};
if (self as #repr) == (Self::#ident_min as #repr) {
None
} else {
// Safety: the number is known to be a valid enum
Some(unsafe { ::core::mem::transmute((self as #repr) - 1) })
}
}
}
} else {
quote! {
/// Returns the previous element before this in value order
#vis fn #ident_next_back(self) -> ::core::option::Option<Self> {
use ::core::iter::DoubleEndedIterator;
use ::core::option::Option::Some;
let mut current = self as #repr;
let mut it = Self::#ident_table_range.iter();
loop {
// Safety: since self/current is an valid enum, one range will match and the iterator will never return None
let r = unsafe { it.next_back().unwrap_unchecked() };
if r.0.contains(¤t){
// Safety: Only when current is type::MIN: the wrapping will happen, but since
// the number will not be in this range and thus the next iter will be used,
// which will be None because this must've been the first element.
current = current.wrapping_sub(1);
if r.0.contains(¤t){
return Some(unsafe { ::core::mem::transmute(current) });
}else{
return it.next_back().map(|r|unsafe { ::core::mem::transmute(*r.0.end()) });
}
}
}
}
}
}
}
}