abi_stable/prefix_type/
pt_metadata.rs

1use std::{borrow::Cow, slice};
2
3#[allow(unused_imports)]
4use crate::{
5    std_types::*,
6    type_layout::{
7        TLData, TLDataDiscriminant, TLField, TLFields, TLFieldsIterator, TLPrefixType, TypeLayout,
8    },
9};
10
11use super::accessible_fields::{FieldAccessibility, FieldConditionality, IsAccessible};
12
13#[allow(unused_imports)]
14use core_extensions::SelfOps;
15
16#[doc(hidden)]
17#[derive(Debug, Clone)]
18pub struct __PrefixTypeMetadata {
19    /// This is the amount of fields on the prefix of the struct,
20    /// which is always the same for the same type,regardless of which library it comes from.
21    pub prefix_field_count: u8,
22
23    pub accessible_fields: FieldAccessibility,
24
25    pub conditional_prefix_fields: FieldConditionality,
26
27    pub fields: __InitialFieldsOrMut,
28
29    /// The layout of the struct,for error messages.
30    pub layout: &'static TypeLayout,
31}
32
33impl __PrefixTypeMetadata {
34    #[allow(dead_code)]
35    #[cfg(feature = "testing")]
36    pub fn new(layout: &'static TypeLayout) -> Self {
37        match layout.data() {
38            TLData::PrefixType(prefix) => Self::with_prefix_layout(prefix, layout),
39            _ => panic!(
40                "Attempting to construct a __PrefixTypeMetadata from a \
41                 TypeLayout of a non-prefix-type.\n\
42                 Type:{}\nDataVariant:{:?}\nPackage:{}",
43                layout.full_type(),
44                layout.data_discriminant(),
45                layout.package(),
46            ),
47        }
48    }
49
50    pub(crate) fn with_prefix_layout(prefix: TLPrefixType, layout: &'static TypeLayout) -> Self {
51        Self {
52            fields: __InitialFieldsOrMut::from(prefix.fields),
53            accessible_fields: prefix.accessible_fields,
54            conditional_prefix_fields: prefix.conditional_prefix_fields,
55            prefix_field_count: prefix.first_suffix_field,
56            layout,
57        }
58    }
59
60    // #[cfg(test)]
61    // pub(crate) fn assert_valid(&self){
62    //     assert_eq!(self.layout.data.as_discriminant(),TLDataDiscriminant::PrefixType );
63    // }
64
65    /// Returns the maximum prefix.Does not check that they are compatible.
66    ///
67    /// # Preconditions
68    ///
69    /// The prefixes must already have been checked for compatibility.
70    #[allow(dead_code)]
71    #[cfg(feature = "testing")]
72    pub fn max(self, other: Self) -> Self {
73        if self.fields.len() < other.fields.len() {
74            other
75        } else {
76            self
77        }
78    }
79    /// Returns the minimum and maximum prefix.Does not check that they are compatible.
80    ///
81    /// # Preconditions
82    ///
83    /// The prefixes must already have been checked for compatibility.
84    pub(crate) fn min_max(self, other: Self) -> (Self, Self) {
85        if self.fields.len() < other.fields.len() {
86            (self, other)
87        } else {
88            (other, self)
89        }
90    }
91
92    /// Combines the fields from `other` into `self`,
93    /// replacing any innaccessible field with one from `other`.
94    ///
95    /// # Preconditions
96    ///
97    /// This must be called after both were checked for compatibility,
98    /// otherwise fields accessible in both `self` and `other`
99    /// won't be checked for compatibility or copied.
100    pub(crate) fn combine_fields_from(&mut self, other: &Self) {
101        let mut o_fields = other.fields.iter();
102
103        let min_field_count = o_fields.len().min(self.fields.len());
104
105        for (field_i, (t_acc, o_acc)) in self
106            .accessible_fields
107            .iter()
108            .take(min_field_count)
109            .zip(other.accessible_fields.iter().take(min_field_count))
110            .enumerate()
111        {
112            let o_field = o_fields.next().unwrap();
113            if !t_acc.is_accessible() && o_acc.is_accessible() {
114                let t_fields = self.fields.to_mut();
115
116                t_fields[field_i] = o_field.into_owned();
117            }
118        }
119
120        if min_field_count == self.fields.len() {
121            let t_fields = self.fields.to_mut();
122
123            for (i, o_field) in o_fields.enumerate() {
124                let field_i = i + min_field_count;
125
126                t_fields.push(o_field.into_owned());
127                self.accessible_fields = self.accessible_fields.set(field_i, IsAccessible::Yes);
128            }
129        }
130    }
131}
132
133/////////////////////////////////////////////////////////////////////////////////
134
135#[doc(hidden)]
136#[derive(Debug, Clone)]
137pub enum __InitialFieldsOrMut {
138    TLFields(TLFields),
139    Mutable(Vec<TLField>),
140}
141
142impl From<TLFields> for __InitialFieldsOrMut {
143    fn from(this: TLFields) -> Self {
144        __InitialFieldsOrMut::TLFields(this)
145    }
146}
147
148impl __InitialFieldsOrMut {
149    pub fn to_mut(&mut self) -> &mut Vec<TLField> {
150        match self {
151            __InitialFieldsOrMut::Mutable(x) => x,
152            this => {
153                let list = this.iter().map(Cow::into_owned).collect::<Vec<TLField>>();
154                *this = __InitialFieldsOrMut::Mutable(list);
155                match this {
156                    __InitialFieldsOrMut::Mutable(x) => x,
157                    _ => unreachable!(),
158                }
159            }
160        }
161    }
162    pub fn iter(&self) -> IFOMIter<'_> {
163        match self {
164            __InitialFieldsOrMut::TLFields(x) => IFOMIter::TLFields(x.iter()),
165            __InitialFieldsOrMut::Mutable(x) => IFOMIter::Slice(x.iter()),
166        }
167    }
168    pub fn len(&self) -> usize {
169        match self {
170            __InitialFieldsOrMut::TLFields(x) => x.len(),
171            __InitialFieldsOrMut::Mutable(x) => x.len(),
172        }
173    }
174}
175
176#[repr(C)]
177#[derive(Clone, Debug)]
178pub enum IFOMIter<'a> {
179    TLFields(TLFieldsIterator),
180    Slice(slice::Iter<'a, TLField>),
181}
182
183impl<'a> Iterator for IFOMIter<'a> {
184    type Item = Cow<'a, TLField>;
185
186    fn next(&mut self) -> Option<Cow<'a, TLField>> {
187        match self {
188            IFOMIter::TLFields(iter) => iter.next().map(Cow::Owned),
189            IFOMIter::Slice(iter) => iter.next().map(Cow::Borrowed),
190        }
191    }
192
193    fn size_hint(&self) -> (usize, Option<usize>) {
194        match self {
195            IFOMIter::TLFields(iter) => iter.size_hint(),
196            IFOMIter::Slice(iter) => iter.size_hint(),
197        }
198    }
199    fn count(self) -> usize {
200        match self {
201            IFOMIter::TLFields(iter) => iter.count(),
202            IFOMIter::Slice(iter) => iter.count(),
203        }
204    }
205}
206
207impl<'a> std::iter::ExactSizeIterator for IFOMIter<'a> {}