abi_stable_derive/
composite_collections.rs

1//! Helper types for constructing strings and arrays composed of other strings and arrays.
2//!
3//! These datatypes are special-cased for small composite collections ,
4//! whose indices fit in a u16.
5
6use std::{
7    borrow::Borrow,
8    convert::TryFrom,
9    fmt::{Debug, Display},
10    marker::PhantomData,
11    ops::{Add, Range},
12};
13
14use as_derive_utils::{return_syn_err, to_stream};
15
16use proc_macro2::{Span, TokenStream as TokenStream2};
17use quote::ToTokens;
18
19use crate::common_tokens::StartLenTokens;
20
21/// A `{start:16,len:u16}` range.
22pub type SmallStartLen = StartLen<u16>;
23
24/// A `{start:N,len:N}` range.
25#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
26pub struct StartLen<N> {
27    pub start: N,
28    pub len: N,
29}
30
31impl StartLen<u16> {
32    abi_stable_shared::declare_start_len_bit_methods! {}
33}
34
35impl<N> StartLen<N> {
36    #[inline]
37    pub(crate) fn from_start_len(start: usize, len: usize) -> Self
38    where
39        N: TryFrom<usize>,
40        N::Error: Debug,
41    {
42        Self {
43            start: N::try_from(start).unwrap(),
44            len: N::try_from(len).unwrap(),
45        }
46    }
47
48    #[inline]
49    pub const fn new(start: N, len: N) -> Self {
50        Self { start, len }
51    }
52
53    #[allow(dead_code)]
54    pub(crate) fn into_range(self) -> Range<N>
55    where
56        N: Copy + Add<N, Output = N>,
57    {
58        self.start..(self.start + self.len)
59    }
60
61    #[inline]
62    pub(crate) fn tokenizer(self, ctokens: &StartLenTokens) -> StartLenTokenizer<'_, N> {
63        StartLenTokenizer {
64            start: self.start,
65            len: self.len,
66            ctokens,
67        }
68    }
69}
70
71impl StartLen<u16> {
72    pub const DUMMY: Self = Self {
73        start: (1u16 << 15) + 1,
74        len: (1u16 << 15) + 1,
75    };
76
77    pub const EMPTY: Self = Self { start: 0, len: 0 };
78
79    /// The start of this range.
80    #[inline]
81    pub const fn start(self) -> usize {
82        self.start as usize
83    }
84
85    #[inline]
86    pub const fn len(self) -> usize {
87        self.len as usize
88    }
89
90    /// Converts this StartLen to a u32.
91    pub const fn to_u32(self) -> u32 {
92        self.start as u32 | ((self.len as u32) << 16)
93    }
94
95    pub fn check_ident_length(&self, span: Span) -> Result<(), syn::Error> {
96        if self.len > Self::IDENT_MAX_LEN {
97            return_syn_err!(
98                span,
99                "Identifier is too long,it must be at most {} bytes.",
100                Self::IDENT_MAX_LEN,
101            );
102        }
103        Ok(())
104    }
105}
106
107pub struct StartLenTokenizer<'a, N> {
108    start: N,
109    len: N,
110    ctokens: &'a StartLenTokens,
111}
112
113impl<'a, N> ToTokens for StartLenTokenizer<'a, N>
114where
115    N: ToTokens,
116{
117    fn to_tokens(&self, ts: &mut TokenStream2) {
118        use syn::token::{Colon2, Comma, Paren};
119
120        let ct = self.ctokens;
121        to_stream!(ts; ct.start_len,Colon2::default(),ct.new );
122        Paren::default().surround(ts, |ts| {
123            to_stream!(ts; self.start,Comma::default(),self.len );
124        });
125    }
126}
127
128///////////////////////////////////////////////////////////////////////
129
130#[allow(dead_code)]
131pub type SmallCompositeString = CompositeString<u16>;
132
133/// A String-like type,
134/// returning a `{start:16,len:u16}` range from methods that extend it.
135pub struct CompositeString<N> {
136    buffer: String,
137    _integer: PhantomData<N>,
138}
139
140#[allow(dead_code)]
141impl<N> CompositeString<N>
142where
143    N: TryFrom<usize>,
144    N::Error: Debug,
145{
146    pub fn new() -> Self {
147        Self {
148            buffer: String::with_capacity(128),
149            _integer: PhantomData,
150        }
151    }
152
153    fn len(&self) -> usize {
154        self.buffer.len()
155    }
156
157    pub fn push_str(&mut self, s: &str) -> StartLen<N> {
158        let start = self.len();
159        self.buffer.push_str(s);
160        StartLen::from_start_len(start, s.len())
161    }
162
163    pub fn push_display<D>(&mut self, s: &D) -> StartLen<N>
164    where
165        D: Display,
166    {
167        use std::fmt::Write;
168        let start = self.len();
169        let _ = write!(self.buffer, "{}", s);
170        StartLen::from_start_len(start, self.len() - start)
171    }
172
173    #[allow(dead_code)]
174    pub fn extend_with_str<I>(&mut self, separator: &str, iter: I) -> StartLen<N>
175    where
176        I: IntoIterator,
177        I::Item: Borrow<str>,
178    {
179        let start = self.len();
180        for s in iter {
181            self.buffer.push_str(s.borrow());
182            self.buffer.push_str(separator);
183        }
184        StartLen::from_start_len(start, self.len() - start)
185    }
186
187    pub fn extend_with_display<I>(&mut self, separator: &str, iter: I) -> StartLen<N>
188    where
189        I: IntoIterator,
190        I::Item: Display,
191    {
192        use std::fmt::Write;
193        let start = self.len();
194        for elem in iter {
195            let _ = write!(self.buffer, "{}", elem);
196            self.buffer.push_str(separator);
197        }
198        StartLen::from_start_len(start, self.len() - start)
199    }
200
201    pub fn into_inner(self) -> String {
202        self.buffer
203    }
204    pub fn as_inner(&self) -> &str {
205        &self.buffer
206    }
207}
208
209///////////////////////////////////////////////////////////////////////
210
211pub type SmallCompositeVec<T> = CompositeVec<T, u16>;
212
213/// A Vec-like type,
214/// returning a `{start:16,len:u16}` range from methods that extend it.
215pub struct CompositeVec<T, N> {
216    list: Vec<T>,
217    _integer: PhantomData<N>,
218}
219
220#[allow(dead_code)]
221impl<T, N> CompositeVec<T, N>
222where
223    N: TryFrom<usize>,
224    N::Error: Debug,
225{
226    pub fn new() -> Self {
227        Self {
228            list: Vec::new(),
229            _integer: PhantomData,
230        }
231    }
232
233    pub fn with_capacity(capacity: usize) -> Self {
234        Self {
235            list: Vec::with_capacity(capacity),
236            _integer: PhantomData,
237        }
238    }
239
240    fn len(&self) -> usize {
241        self.list.len()
242    }
243
244    pub fn push(&mut self, elem: T) -> u16 {
245        let ind = self.len();
246        self.list.push(elem);
247        ind as u16
248    }
249
250    pub fn extend<I>(&mut self, iter: I) -> StartLen<N>
251    where
252        I: IntoIterator<Item = T>,
253    {
254        let start = self.len();
255        self.list.extend(iter);
256        StartLen::from_start_len(start, self.len() - start)
257    }
258
259    pub fn into_inner(self) -> Vec<T> {
260        self.list
261    }
262    pub fn as_inner(&self) -> &[T] {
263        &self.list
264    }
265}