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
use ::itertools::Itertools;
use ::syn::*;
use crate::helpers::*;
pub struct Behavior;
impl super::Behavior for Behavior {
fn is(&self, _: &Type) -> bool {
true
}
fn imports(&self, sty: &Type, pkg: &str, crate_name: &str) -> Vec<String> {
import_from_type(sty, pkg, crate_name).map(|i| vec![i]).unwrap_or_else(|| vec![])
}
fn name(&self, _sty: &Type) -> String { "struct".to_owned() }
fn ffi(&self, sty: &Type) -> String {
format!("Pointer<{}>", type_name_from_path(sty))
}
fn native(&self, sty: &Type) -> String {
type_name_from_path(sty)
}
fn native_to_ffi(&self, _sty: &Type, expr: String) -> String {
format!("{}.addressOf", expr)
}
fn ffi_to_native(&self, _sty: &Type, expr: String) -> String {
format!("{}.ref", expr)
}
}
fn import_from_type(sty: &Type, pkg: &str, crate_name: &str) -> Option<String> {
if let Type::Path(tp) = sty {
import_from_path(&tp.path, pkg, crate_name)
} else {
panic!("only normal type of kind typepath supported")
}
}
fn import_from_path(path: &Path, pkg: &str, crate_name: &str) -> Option<String> {
let mut segments = path.segments.iter().peekable();
let first = segments.next().expect(">0 segments always");
let first_str = first.ident.to_string();
if first_str == "super" {
panic!("type paths using the 'super' keyword are forbidden")
} else if first_str == "crate" {
if let Some(path) = segments_to_import_path(segments) {
Some(format!("package:{}/{}/{}.dart", pkg, crate_name, path))
} else {
Some(format!("package:{}/{}.dart", pkg, crate_name))
}
} else if segments.peek().is_some() {
Some(format!(
"package:{}/{}.dart",
pkg,
segments_to_import_path(::std::iter::once(first).chain(segments)).expect(""),
))
} else {
None
}
}
fn segments_to_import_path<'a, I: Iterator<Item=&'a PathSegment>>(segments: I) -> Option<String> {
let mut elements: Vec<String> = segments.map(|seg| {
let ident = seg.ident.to_string();
if ident == "super" {
"..".to_string()
} else if ident == "crate" {
panic!("cannot use keyword 'crate' in the middle of a type path")
} else {
ident
}
}).collect();
if elements.len() > 2 {
Some(elements.chunks_exact(elements.len()-1).flatten().join("/"))
} else if elements.len() == 2 {
Some(elements.remove(0))
} else {
None
}
}