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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use crate::authoring::*;

// ----- B U I L T I N   O P E R A T O R S ---------------------------------------------

// Install new builtin operators by adding them in the `mod` and
// `BUILTIN_OPERATORS` blocks below

mod adapt;
mod addone;
mod btmerc;
mod cart;
mod curvature;
mod deformation;
mod geodesic;
mod gridshift;
mod helmert;
mod iso6709;
mod laea;
mod latitude;
mod lcc;
mod merc;
mod molodensky;
mod noop;
mod omerc;
pub(crate) mod pipeline; // Needed by Op for instantiation
mod somerc;
mod tmerc;
mod unitconvert;
mod units;
mod webmerc;

#[rustfmt::skip]
const BUILTIN_OPERATORS: [(&str, OpConstructor); 31] = [
    ("adapt",        OpConstructor(adapt::new)),
    ("addone",       OpConstructor(addone::new)),
    ("btmerc",       OpConstructor(btmerc::new)),
    ("butm",         OpConstructor(btmerc::utm)),
    ("cart",         OpConstructor(cart::new)),
    ("curvature",    OpConstructor(curvature::new)),
    ("deformation",  OpConstructor(deformation::new)),
    ("dm",           OpConstructor(iso6709::dm)),
    ("dms",          OpConstructor(iso6709::dms)),
    ("geodesic",     OpConstructor(geodesic::new)),
    ("gridshift",    OpConstructor(gridshift::new)),
    ("helmert",      OpConstructor(helmert::new)),
    ("laea",         OpConstructor(laea::new)),
    ("latitude",     OpConstructor(latitude::new)),
    ("lcc",          OpConstructor(lcc::new)),
    ("merc",         OpConstructor(merc::new)),
    ("webmerc",      OpConstructor(webmerc::new)),
    ("molodensky",   OpConstructor(molodensky::new)),
    ("noop",         OpConstructor(noop::new)),
    ("omerc",        OpConstructor(omerc::new)),
    ("somerc",       OpConstructor(somerc::new)),
    ("tmerc",        OpConstructor(tmerc::new)),
    ("utm",          OpConstructor(tmerc::utm)),
    ("unitconvert", OpConstructor(unitconvert::new)),
    ("pipeline",     OpConstructor(pipeline::new)),
    ("pop",          OpConstructor(pipeline::pop)),
    ("push",         OpConstructor(pipeline::push)),

    // Some commonly used noop-aliases
    ("longlat",      OpConstructor(noop::new)),
    ("latlon",       OpConstructor(noop::new)),
    ("latlong",      OpConstructor(noop::new)),
    ("lonlat",       OpConstructor(noop::new)),
];
// A BTreeMap would have been a better choice for BUILTIN_OPERATORS, except
// for the annoying fact that it cannot be compile-time const-constructed.

/// Handle instantiation of built-in operators, as defined in
/// `BUILTIN_OPERATORS` above.
pub(crate) fn builtin(name: &str) -> Result<OpConstructor, Error> {
    for p in BUILTIN_OPERATORS {
        if p.0 == name {
            return Ok(p.1);
        }
    }
    Err(Error::NotFound(name.to_string(), String::default()))
}

// ----- S T R U C T   O P C O N S T R U C T O R ---------------------------------------

/// Blueprint for the overall instantiation of an operator.
///
/// OpConstructor needs to be a newtype, rather than a type alias,
/// since we must implement the Debug-trait for OpConstructor (to
/// make auto derive of the Debug-trait work for any derived type).
pub struct OpConstructor(pub fn(args: &RawParameters, ctx: &dyn Context) -> Result<Op, Error>);

// Cannot autoderive the Debug trait
impl core::fmt::Debug for OpConstructor {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "OpConstructor")
    }
}

// ----- S T R U C T   I N N E R O P ---------------------------------------------------

/// Blueprint for the functions doing the actual transformation work.
///
/// InnerOp needs to be a newtype, rather than a type alias, since we
/// must implement the Debug-trait for InnerOp (to make auto derive
/// of the Debug-trait work for any derived type).
pub struct InnerOp(pub fn(op: &Op, ctx: &dyn Context, operands: &mut dyn CoordinateSet) -> usize);

// Cannot autoderive the Debug trait
impl core::fmt::Debug for InnerOp {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "InnerOp")
    }
}

// Defaults to no_op
impl Default for InnerOp {
    fn default() -> InnerOp {
        InnerOp(noop_placeholder)
    }
}

fn noop_placeholder(_op: &Op, _ctx: &dyn Context, _operands: &mut dyn CoordinateSet) -> usize {
    // Consider whether this should return an Err-value if used as a placeholder for a
    // non-existing or non-implemented inverse operation
    0
}