1
+ # An ImmutableDict constructor based on a list of Pair arguments has been introduced in Julia 1.6.0 and backported to Julia 1.5
2
+ if VERSION < v " 1.5"
3
+ function Base. ImmutableDict (KV:: Pair{K,V} , KVs:: Pair{K,V} ...) where {K,V}
4
+ d = Base. ImmutableDict (KV)
5
+ for p in KVs
6
+ d = Base. ImmutableDict (d, p)
7
+ end
8
+ return d
9
+ end
10
+ end
11
+
1
12
"""
2
- @convert(args...)
13
+ @convert(<T1>::<T2>,
14
+ <conversions>
15
+ )
16
+
17
+ Generate `convert` functions both ways between ArchGDAL Enum of typeids (e.g. `ArchGDAL.OGRFieldType`)
18
+ and other types or typeids.
19
+
20
+ ArchGDAL uses Enum types, listing typeids of various data container used in GDAL/OGR object model.
21
+ Some of these types are used to implement concrete types in julia through parametric composite types
22
+ based on those Enum of typeids (e.g. `Geometry` and `IGeometry` types with `OGRwkbGeometryType`)
23
+
24
+ Other types or typeids can be:
25
+ - GDAL CEnum.Cenum typeids (e.g. `GDAL.OGRFieldType`),
26
+ - Base primitive DataType types (e.g. `Bool`),
27
+ - other parametric composite types (e.g. `ImageCore.Normed`)
28
+
29
+ # Arguments
30
+ - `(<T1>::<T2>)::Expr`: source and target supertypes, where `T1<:Enum` and `T2<:CEnum.Cenum || T2::Type{DataType} || T2::UnionAll}``
31
+ - `(<stype1>::<stype2>)::Expr`: source and target subtypes or type ids with `stype1::T1` and
32
+ - `stype2::T2 where T2<:CEnum.Cenum` or
33
+ - `stype2::T2 where T2::Type{DataType}` or
34
+ - `stype2<:T2`where T2<:UnionAll
35
+ - ...
36
+
37
+ **Note:** In the case where the mapping is not bijective, the last declared typeid of subtype is used.
38
+ Example:
39
+ ```
40
+ @convert(
41
+ OGRFieldType::DataType,
42
+ OFTInteger::Bool,
43
+ OFTInteger::Int16,
44
+ OFTInteger::Int32,
45
+ )
46
+ ```
47
+ will generate a `convert` functions giving:
48
+ - `Int32` type for `OFTInteger` and not `Ìnt16`
49
+ - `OFTInteger` OGRFieldType typeid for both `Int16` and `Int32`
3
50
4
- # General case:
51
+ # Usage
52
+ ### General case:
5
53
```
6
- eval( @convert(GDALRWFlag::GDAL.GDALRWFlag,
54
+ @convert(GDALRWFlag::GDAL.GDALRWFlag,
7
55
GF_Read::GDAL.GF_Read,
8
56
GF_Write::GDAL.GF_Write,
9
- ))
57
+ )
10
58
```
11
59
does the equivalent of
12
60
```
13
- const GDALRWFlag_to_GDALRWFlag_map = Dict (
61
+ const GDALRWFlag_to_GDALRWFlag_map = ImmutableDict (
14
62
GF_Read => GDAL.GF_Read,
15
63
GF_Write => GDAL.GF_Write
16
64
)
17
65
Base.convert(::Type{GDAL.GDALRWFlag}, ft::GDALRWFlag) =
18
66
GDALRWFlag_to_GDALRWFlag_map[ft]
19
67
20
- const GDALRWFlag_to_GDALRWFlag_map = Dict (
68
+ const GDALRWFlag_to_GDALRWFlag_map = ImmutableDict (
21
69
GDAL.GF_Read => GF_Read,
22
70
GDAL.GF_Write => GF_Write
23
71
)
24
72
Base.convert(::Type{GDALRWFlag}, ft::GDAL.GDALRWFlag) =
25
73
GDALRWFlag_to_GDALRWFlag_map[ft]
26
74
```
27
- # Case where 1st type `<: Enum` and 2nd type `== DataType` or ìsa UnionAll`:
75
+ ### Case where 1st type `<: Enum` and 2nd type `== DataType` or ` ìsa UnionAll`:
28
76
```
29
- eval( @convert(OGRFieldType::DataType,
77
+ @convert(OGRFieldType::DataType,
30
78
OFTInteger::Bool,
31
79
OFTInteger::Int16,
32
- ))
80
+ )
33
81
```
34
82
does the equivalent of
35
83
```
36
- const OGRFieldType_to_DataType_map = Dict (
84
+ const OGRFieldType_to_DataType_map = ImmutableDict (
37
85
OFTInteger => Bool,
38
86
OFTInteger => Int16,
39
87
)
@@ -46,46 +94,48 @@ Base.convert(::Type{OGRFieldType}, ft::Type{Int16}) = OFTInteger
46
94
47
95
"""
48
96
macro convert (args... )
49
- @assert length (args) > 0
97
+ @assert length (args) > 1
50
98
@assert args[1 ]. head == :(:: )
51
- type1_symbol = args[1 ]. args[1 ]
52
- type2_symbol = args[1 ]. args[2 ]
53
- type1_string = replace (string (type1_symbol), " ." => " _" )
54
- type2_string = replace (string (type2_symbol), " ." => " _" )
55
- type1_isenum_and_type2_equaldatatype_or_isaunionall =
56
- (eval (type1_symbol) <: Enum ) &&
57
- ((eval (type2_symbol) == DataType) || (eval (type2_symbol) isa UnionAll))
58
- type1 = esc (type1_symbol)
59
- type2 = esc (type2_symbol)
60
- fwd_map = Expr[Expr (:tuple , esc .(a. args)... ) for a in args[2 : end ]]
61
- if type1_isenum_and_type2_equaldatatype_or_isaunionall
62
- rev_to_enum_map = [Tuple (esc .(reverse (a. args))) for a in args[2 : end ]]
63
- else
64
- rev_map =
65
- Expr[Expr (:tuple , esc .(reverse (a. args))... ) for a in args[2 : end ]]
66
- end
99
+ (T1, T2) = args[1 ]. args
100
+
101
+ # Types and type ids / subtypes checks
102
+ stypes1, stypes2 = zip ((eval .(a. args) for a in args[2 : end ]). .. )
103
+ @assert (eval (T1) <: Enum && all (isa .(stypes1, eval (T1))))
104
+ @assert (
105
+ ((eval (T2) <: CEnum.Cenum ) && all (isa .(stypes2, eval (T2)))) ||
106
+ ((eval (T2) isa Type{DataType}) && all (isa .(stypes2, eval (T2)))) ||
107
+ ((eval (T2) isa UnionAll) && all ((< :). (stypes2, eval (T2))))
108
+ )
109
+
110
+ # Types other representations
111
+ (T1_string, T2_string) = replace .(string .((T1, T2)), " ." => " _" )
112
+ (type1, type2) = esc .((T1, T2))
113
+
114
+ # Subtypes forward and backward mapping
115
+ fwd_map = [Expr (:call , esc (:Pair ), esc .(a. args)... ) for a in args[2 : end ]]
116
+ rev_map =
117
+ [Expr (:call , esc (:Pair ), esc .(reverse (a. args))... ) for a in args[2 : end ]]
67
118
119
+ # ! Convert functions generation
68
120
result_expr = Expr (:block )
69
- # Forward conversion (no case of 1st type == DataType and 2nd type <: Enum handled)
70
- type1_to_type2_map_name =
71
- esc (Symbol (type1_string * " _to_" * type2_string * " _map" ))
121
+
122
+ # * Forward conversions from ArchGDAL typeids
123
+ T1_to_T2_map_name = esc (Symbol (T1_string * " _to_" * T2_string * " _map" ))
72
124
push! (
73
125
result_expr. args,
74
- :(const $ type1_to_type2_map_name = Dict ([$ (fwd_map... )])),
126
+ :(const $ T1_to_T2_map_name = Base . ImmutableDict ([$ (fwd_map... )]. .. )),
75
127
)
76
128
push! (
77
129
result_expr. args,
78
130
:(function Base. convert (:: Type{$type2} , ft:: $type1 )
79
- return get ($ type1_to_type2_map_name, ft) do
80
- return error (" Unknown type: $ft " )
81
- end
131
+ return $ T1_to_T2_map_name[ft]
82
132
end ),
83
133
)
84
- # Reverse conversion
85
- if type1_isenum_and_type2_equaldatatype_or_isaunionall
86
- for stypes in rev_to_enum_map
87
- eval (type2_symbol) isa UnionAll &&
88
- @assert eval (stypes[ 1 ] . args[1 ]) <: eval (type2_symbol)
134
+
135
+ # * Reverse conversions to ArchGDAL typeids
136
+ # Optimization for conversion from types
137
+ if ! ( eval (T2) <: CEnum.Cenum )
138
+ for stypes in [ Tuple ( esc .( reverse (a . args))) for a in args[2 : end ]]
89
139
push! (
90
140
result_expr. args,
91
141
:(
@@ -98,22 +148,24 @@ macro convert(args...)
98
148
),
99
149
)
100
150
end
151
+ # Conversion from typeids
101
152
else
102
- type2_to_type1_map_name =
103
- esc (Symbol (type2_string * " _to_" * type1_string * " _map" ))
153
+ T2_to_T1_map_name = esc (Symbol (T2_string * " _to_" * T1_string * " _map" ))
104
154
push! (
105
155
result_expr. args,
106
- :(const $ type2_to_type1_map_name = Dict ([$ (rev_map... )])),
156
+ :(
157
+ const $ T2_to_T1_map_name =
158
+ Base. ImmutableDict ([$ (rev_map... )]. .. )
159
+ ),
107
160
)
108
161
push! (
109
162
result_expr. args,
110
163
:(function Base. convert (:: Type{$type1} , ft:: $type2 )
111
- return get ($ type2_to_type1_map_name, ft) do
112
- return error (" Unknown type: $ft " )
113
- end
164
+ return $ T2_to_T1_map_name[ft]
114
165
end ),
115
166
)
116
167
end
168
+
117
169
return result_expr
118
170
end
119
171
0 commit comments