ritual/
rust_type.rs

1//use common::errors::{unexpected, ResultExt, Result};
2//use common::string_utils::CaseOperations;
3//use common::utils::MapIfOk;
4//use cpp_ffi_data::CppIndirectionChange;
5//use cpp_type::CppType;
6use serde_derive::{Deserialize, Serialize};
7
8/// Rust identifier. Represented by
9/// a vector of name parts. For a regular name,
10/// first part is name of the crate,
11/// last part is own name of the entity,
12/// and intermediate names are module names.
13/// Built-in types are represented
14/// by a single vector item, like `vec!["i32"]`.
15#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
16pub struct RustPath {
17    /// Parts of the name
18    pub parts: Vec<String>,
19}
20
21/*
22/// Conversion from public Rust API type to
23/// the corresponding FFI type
24#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
25#[allow(dead_code)]
26pub enum RustToCTypeConversion {
27  /// Types are the same
28  None,
29  /// `&T` to `*const T` (or similar mutable types)
30  RefToPtr,
31  /// `Option<&T>` to `*const T` (or similar mutable types)
32  OptionRefToPtr,
33  /// `T` to `*const T` (or similar mutable type)
34  ValueToPtr,
35  /// `CppBox<T>` to `*const T` (or similar mutable type)
36  CppBoxToPtr,
37  /// `qt_core::flags::Flags<T>` to `libc::c_uint`
38  QFlagsToUInt,
39}
40
41/// Information about a completely processed type
42/// including its variations at each processing step.
43#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
44pub struct CompleteType {
45  /// Original C++ type used in the C++ library's API
46  pub cpp_type: CppType,
47  /// C++ type used in the C++ wrapper library's API
48  pub cpp_ffi_type: CppType,
49  /// Conversion from `cpp_type` to `cpp_ffi_type`
50  pub cpp_to_ffi_conversion: CppIndirectionChange,
51  /// Rust type used in FFI functions
52  /// (must be exactly the same as `cpp_ffi_type`)
53  pub rust_ffi_type: RustType,
54  /// Type used in public Rust API
55  pub rust_api_type: RustType,
56  /// Conversion from `rust_api_type` to `rust_ffi_type`
57  pub rust_api_to_c_conversion: RustToCTypeConversion,
58}
59
60/// Indirection of a Rust type
61#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
62pub enum RustTypeIndirection {
63  /// No indirection
64  None,
65  /// Raw pointer
66  Ptr,
67  /// Reference with a lifetime
68  Ref { lifetime: Option<String> },
69  /// Raw pointer to raw pointer
70  PtrPtr,
71  /// Raw pointer to reference
72  PtrRef { lifetime: Option<String> },
73}
74
75/// A Rust type
76#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
77pub enum RustType {
78  /// Empty tuple `()`, used as the replacement of C++'s `void` type.
79  EmptyTuple,
80  /// A numeric, enum or struct type with some indirection
81  Common {
82    /// Full name of the base type
83    base: RustName,
84    /// Generic arguments, if any
85    generic_arguments: Option<Vec<RustType>>,
86    /// If the type has no indirection, `is_const`
87    /// indicates constness of the type itself (e.g. `i32` vs `mut i32`).
88    /// If the type has one level of indirection, `is_const`
89    /// indicates constness of that indirection, i.e. if the pointer or the reference
90    /// is const. If the type has two levels of indirection,
91    /// `is_const` indicates constness of indirection that is applied first.
92    is_const: bool,
93    /// If the type has two levels of indirection,
94    /// `is_const2` indicates constness of indirection that is applied second.
95    /// In other cases it is `false`.
96    is_const2: bool,
97    /// Indirection of this type.
98    indirection: RustTypeIndirection,
99  },
100  /// A function pointer type.
101  FunctionPointer {
102    /// Return type of the function.
103    return_type: Box<RustType>,
104    /// Argument types of the function.
105    arguments: Vec<RustType>,
106  },
107}
108
109impl RustName {
110  /// Creates new `RustName` consisting of `parts`.
111  pub fn new(parts: Vec<String>) -> Result<RustName> {
112    if parts.is_empty() {
113      return Err(unexpected("RustName can't be empty").into());
114    }
115    Ok(RustName { parts: parts })
116  }
117
118  /// Returns crate name of this name, or `None`
119  /// if this name does not contain the crate name.
120  pub fn crate_name(&self) -> Option<&String> {
121    assert!(self.parts.len() > 0);
122    if self.parts.len() > 1 {
123      Some(&self.parts[0])
124    } else {
125      None
126    }
127  }
128
129  /// Returns last component of the name.
130  pub fn last_name(&self) -> Result<&String> {
131    self
132      .parts
133      .last()
134      .with_context(|| unexpected("RustName can't be empty"))
135  }
136
137  /// Returns formatted name for using within `current_crate`.
138  /// If `current_crate` is `None`, it's assumed that the formatted name
139  /// will be used outside of the crate it belongs to.
140  pub fn full_name(&self, current_crate: Option<&str>) -> String {
141    if let Some(current_crate) = current_crate {
142      if let Some(self_crate) = self.crate_name() {
143        if self_crate == current_crate {
144          return format!("::{}", self.parts[1..].join("::"));
145        }
146      }
147    }
148    if self.parts.len() == 1 {
149      self.parts[0].clone()
150    } else {
151      format!("::{}", self.parts.join("::"))
152    }
153  }
154
155  /// Returns true if `other` is nested within `self`.
156  pub fn includes(&self, other: &RustName) -> bool {
157    let extra_modules_count = other.parts.len() as isize - self.parts.len() as isize;
158    extra_modules_count > 0 && other.parts[0..self.parts.len()] == self.parts[..]
159  }
160
161  /// Returns true if `other` is a direct child of `self`.
162  pub fn includes_directly(&self, other: &RustName) -> bool {
163    let extra_modules_count = other.parts.len() as isize - self.parts.len() as isize;
164    self.includes(other) && extra_modules_count == 1
165  }
166}
167
168impl RustType {
169  /// Returns alphanumeric description of this type
170  /// for purposes of name disambiguation.
171  #[allow(dead_code)]
172  pub fn caption(&self, context: &RustName) -> Result<String> {
173    Ok(match *self {
174      RustType::EmptyTuple => "empty".to_string(),
175      RustType::Common {
176        ref base,
177        ref generic_arguments,
178        ref is_const,
179        ref is_const2,
180        ref indirection,
181      } => {
182        let mut name = if base.parts.len() == 1 {
183          base.parts[0].to_snake_case()
184        } else {
185          let mut remaining_context: &[String] = &context.parts;
186          let mut parts: &[String] = &base.parts;
187          if &parts[0] == "libc" {
188            parts = &parts[1..];
189          };
190          let mut good_parts = Vec::new();
191          for part in parts {
192            if !remaining_context.is_empty() && part == &remaining_context[0] {
193              remaining_context = &remaining_context[1..];
194            } else {
195              remaining_context = &[];
196              let snake_part = part.to_snake_case();
197              if good_parts.last() != Some(&snake_part) {
198                good_parts.push(snake_part);
199              } else {
200              }
201            }
202          }
203          if good_parts.is_empty() {
204            base.last_name()?.clone()
205          } else {
206            good_parts.join("_")
207          }
208        };
209        if let Some(ref args) = *generic_arguments {
210          name = format!(
211            "{}_{}",
212            name,
213            args.iter().map_if_ok(|x| x.caption(context))?.join("_")
214          );
215        }
216        let mut_text = if *is_const { "" } else { "_mut" };
217        match *indirection {
218          RustTypeIndirection::None => {}
219          RustTypeIndirection::Ref { .. } => {
220            name = format!("{}{}_ref", name, mut_text);
221          }
222          RustTypeIndirection::Ptr => {
223            name = format!("{}{}_ptr", name, mut_text);
224          }
225          RustTypeIndirection::PtrPtr => {
226            let mut_text2 = if *is_const2 { "" } else { "_mut" };
227            name = format!("{}{}_ptr{}_ptr", name, mut_text, mut_text2);
228          }
229          RustTypeIndirection::PtrRef { .. } => {
230            let mut_text2 = if *is_const2 { "" } else { "_mut" };
231            name = format!("{}{}_ptr{}_ref", name, mut_text, mut_text2);
232          }
233        }
234        name
235      }
236      RustType::FunctionPointer { .. } => "fn".to_string(),
237    })
238  }
239
240  /// Returns true if this type is a reference.
241  #[allow(dead_code)]
242  pub fn is_ref(&self) -> bool {
243    match *self {
244      RustType::Common {
245        ref indirection, ..
246      } => match *indirection {
247        RustTypeIndirection::Ref { .. } | RustTypeIndirection::PtrRef { .. } => true,
248        _ => false,
249      },
250      RustType::EmptyTuple | RustType::FunctionPointer { .. } => false,
251    }
252  }
253
254  /// Returns a copy of this type with `new_lifetime` added, if possible.
255  pub fn with_lifetime(&self, new_lifetime: String) -> RustType {
256    let mut r = self.clone();
257    if let RustType::Common {
258      ref mut indirection,
259      ..
260    } = r
261    {
262      match *indirection {
263        RustTypeIndirection::Ref { ref mut lifetime }
264        | RustTypeIndirection::PtrRef { ref mut lifetime } => *lifetime = Some(new_lifetime),
265        _ => {}
266      }
267    }
268    r
269  }
270
271  /// Returns name of the lifetime of this type,
272  /// or `None` if there isn't any lifetime in this type.
273  pub fn lifetime(&self) -> Option<&String> {
274    match *self {
275      RustType::Common {
276        ref indirection, ..
277      } => match *indirection {
278        RustTypeIndirection::Ref { ref lifetime }
279        | RustTypeIndirection::PtrRef { ref lifetime } => lifetime.as_ref(),
280        _ => None,
281      },
282      _ => None,
283    }
284  }
285  /// Returns true if indirection that is applied last has const qualifier.
286  pub fn last_is_const(&self) -> Result<bool> {
287    if let RustType::Common {
288      ref is_const,
289      ref is_const2,
290      ref indirection,
291      ..
292    } = *self
293    {
294      match *indirection {
295        RustTypeIndirection::PtrPtr { .. } | RustTypeIndirection::PtrRef { .. } => Ok(*is_const2),
296        _ => Ok(*is_const),
297      }
298    } else {
299      Err("not a Common type".into())
300    }
301  }
302
303  /// Returns true if this type (or first indirection of the type) is const.
304  pub fn is_const(&self) -> Result<bool> {
305    match *self {
306      RustType::Common { ref is_const, .. } => Ok(*is_const),
307      _ => Err("not a Common type".into()),
308    }
309  }
310
311  /// Sets value of `is_const` for a common type.
312  pub fn set_const(&mut self, value: bool) -> Result<()> {
313    match *self {
314      RustType::Common {
315        ref mut is_const, ..
316      } => {
317        *is_const = value;
318        Ok(())
319      }
320      _ => Err("not a Common type".into()),
321    }
322  }
323
324  /// Returns true if function with an argument of type `self`
325  /// should be assumed unsafe. Currently returns true if this type
326  /// is or contains a raw pointer.
327  pub fn is_unsafe_argument(&self) -> bool {
328    match *self {
329      RustType::Common {
330        ref indirection,
331        ref base,
332        ref generic_arguments,
333        ..
334      } => {
335        match *indirection {
336          RustTypeIndirection::None | RustTypeIndirection::Ref { .. } => {}
337          RustTypeIndirection::Ptr
338          | RustTypeIndirection::PtrPtr
339          | RustTypeIndirection::PtrRef { .. } => {
340            return true;
341          }
342        }
343        if base.full_name(None) == "std::option::Option" {
344          if let Some(ref args) = *generic_arguments {
345            if let Some(ref arg) = args.get(0) {
346              if arg.is_unsafe_argument() {
347                return true;
348              }
349            }
350          }
351        }
352        false
353      }
354      RustType::EmptyTuple => false,
355      RustType::FunctionPointer { .. } => true,
356    }
357  }
358}
359
360impl CompleteType {
361  /// Converts Rust API type from pointer to reference
362  /// and modifies `rust_api_to_c_conversion` accordingly.
363  /// `is_const1` specifies new constness of the created reference.
364  pub fn ptr_to_ref(&self, is_const1: bool) -> Result<CompleteType> {
365    let mut r = self.clone();
366    if let RustType::Common {
367      ref mut is_const,
368      ref mut indirection,
369      ..
370    } = r.rust_api_type
371    {
372      if *indirection != RustTypeIndirection::Ptr {
373        return Err("not a pointer type".into());
374      }
375      *indirection = RustTypeIndirection::Ref { lifetime: None };
376      *is_const = is_const1;
377    } else {
378      return Err("not a RustType::Common".into());
379    }
380    if r.rust_api_to_c_conversion != RustToCTypeConversion::None {
381      return Err("rust_api_to_c_conversion is not none".into());
382    }
383    r.rust_api_to_c_conversion = RustToCTypeConversion::RefToPtr;
384    Ok(r)
385  }
386
387  /// Converts Rust API type from pointer to value
388  /// and modifies `rust_api_to_c_conversion` accordingly.
389  pub fn ptr_to_value(&self) -> Result<CompleteType> {
390    let mut r = self.clone();
391    if let RustType::Common {
392      ref mut is_const,
393      ref mut indirection,
394      ..
395    } = r.rust_api_type
396    {
397      if *indirection != RustTypeIndirection::Ptr {
398        return Err("not a pointer type".into());
399      }
400      *indirection = RustTypeIndirection::None;
401      *is_const = true;
402    } else {
403      return Err("not a RustType::Common".into());
404    }
405    if r.rust_api_to_c_conversion != RustToCTypeConversion::None {
406      return Err("rust_api_to_c_conversion is not none".into());
407    }
408    r.rust_api_to_c_conversion = RustToCTypeConversion::ValueToPtr;
409    Ok(r)
410  }
411}
412*/