xref: /third_party/rust/crates/cxx/syntax/trivial.rs (revision 33d722a9)
133d722a9Sopenharmony_ciuse crate::syntax::map::UnorderedMap;
233d722a9Sopenharmony_ciuse crate::syntax::set::{OrderedSet as Set, UnorderedSet};
333d722a9Sopenharmony_ciuse crate::syntax::{Api, Enum, ExternFn, NamedType, Pair, Struct, Type};
433d722a9Sopenharmony_ciuse proc_macro2::Ident;
533d722a9Sopenharmony_ciuse std::fmt::{self, Display};
633d722a9Sopenharmony_ci
733d722a9Sopenharmony_ci#[derive(Copy, Clone)]
833d722a9Sopenharmony_cipub enum TrivialReason<'a> {
933d722a9Sopenharmony_ci    StructField(&'a Struct),
1033d722a9Sopenharmony_ci    FunctionArgument(&'a ExternFn),
1133d722a9Sopenharmony_ci    FunctionReturn(&'a ExternFn),
1233d722a9Sopenharmony_ci    BoxTarget,
1333d722a9Sopenharmony_ci    VecElement,
1433d722a9Sopenharmony_ci    SliceElement { mutable: bool },
1533d722a9Sopenharmony_ci    UnpinnedMut(&'a ExternFn),
1633d722a9Sopenharmony_ci}
1733d722a9Sopenharmony_ci
1833d722a9Sopenharmony_cipub fn required_trivial_reasons<'a>(
1933d722a9Sopenharmony_ci    apis: &'a [Api],
2033d722a9Sopenharmony_ci    all: &Set<&'a Type>,
2133d722a9Sopenharmony_ci    structs: &UnorderedMap<&'a Ident, &'a Struct>,
2233d722a9Sopenharmony_ci    enums: &UnorderedMap<&'a Ident, &'a Enum>,
2333d722a9Sopenharmony_ci    cxx: &UnorderedSet<&'a Ident>,
2433d722a9Sopenharmony_ci) -> UnorderedMap<&'a Ident, Vec<TrivialReason<'a>>> {
2533d722a9Sopenharmony_ci    let mut required_trivial = UnorderedMap::new();
2633d722a9Sopenharmony_ci
2733d722a9Sopenharmony_ci    let mut insist_extern_types_are_trivial = |ident: &'a NamedType, reason| {
2833d722a9Sopenharmony_ci        if cxx.contains(&ident.rust)
2933d722a9Sopenharmony_ci            && !structs.contains_key(&ident.rust)
3033d722a9Sopenharmony_ci            && !enums.contains_key(&ident.rust)
3133d722a9Sopenharmony_ci        {
3233d722a9Sopenharmony_ci            required_trivial
3333d722a9Sopenharmony_ci                .entry(&ident.rust)
3433d722a9Sopenharmony_ci                .or_insert_with(Vec::new)
3533d722a9Sopenharmony_ci                .push(reason);
3633d722a9Sopenharmony_ci        }
3733d722a9Sopenharmony_ci    };
3833d722a9Sopenharmony_ci
3933d722a9Sopenharmony_ci    for api in apis {
4033d722a9Sopenharmony_ci        match api {
4133d722a9Sopenharmony_ci            Api::Struct(strct) => {
4233d722a9Sopenharmony_ci                for field in &strct.fields {
4333d722a9Sopenharmony_ci                    if let Type::Ident(ident) = &field.ty {
4433d722a9Sopenharmony_ci                        let reason = TrivialReason::StructField(strct);
4533d722a9Sopenharmony_ci                        insist_extern_types_are_trivial(ident, reason);
4633d722a9Sopenharmony_ci                    }
4733d722a9Sopenharmony_ci                }
4833d722a9Sopenharmony_ci            }
4933d722a9Sopenharmony_ci            Api::CxxFunction(efn) | Api::RustFunction(efn) => {
5033d722a9Sopenharmony_ci                if let Some(receiver) = &efn.receiver {
5133d722a9Sopenharmony_ci                    if receiver.mutable && !receiver.pinned {
5233d722a9Sopenharmony_ci                        let reason = TrivialReason::UnpinnedMut(efn);
5333d722a9Sopenharmony_ci                        insist_extern_types_are_trivial(&receiver.ty, reason);
5433d722a9Sopenharmony_ci                    }
5533d722a9Sopenharmony_ci                }
5633d722a9Sopenharmony_ci                for arg in &efn.args {
5733d722a9Sopenharmony_ci                    match &arg.ty {
5833d722a9Sopenharmony_ci                        Type::Ident(ident) => {
5933d722a9Sopenharmony_ci                            let reason = TrivialReason::FunctionArgument(efn);
6033d722a9Sopenharmony_ci                            insist_extern_types_are_trivial(ident, reason);
6133d722a9Sopenharmony_ci                        }
6233d722a9Sopenharmony_ci                        Type::Ref(ty) => {
6333d722a9Sopenharmony_ci                            if ty.mutable && !ty.pinned {
6433d722a9Sopenharmony_ci                                if let Type::Ident(ident) = &ty.inner {
6533d722a9Sopenharmony_ci                                    let reason = TrivialReason::UnpinnedMut(efn);
6633d722a9Sopenharmony_ci                                    insist_extern_types_are_trivial(ident, reason);
6733d722a9Sopenharmony_ci                                }
6833d722a9Sopenharmony_ci                            }
6933d722a9Sopenharmony_ci                        }
7033d722a9Sopenharmony_ci                        _ => {}
7133d722a9Sopenharmony_ci                    }
7233d722a9Sopenharmony_ci                }
7333d722a9Sopenharmony_ci                if let Some(ret) = &efn.ret {
7433d722a9Sopenharmony_ci                    match ret {
7533d722a9Sopenharmony_ci                        Type::Ident(ident) => {
7633d722a9Sopenharmony_ci                            let reason = TrivialReason::FunctionReturn(efn);
7733d722a9Sopenharmony_ci                            insist_extern_types_are_trivial(ident, reason);
7833d722a9Sopenharmony_ci                        }
7933d722a9Sopenharmony_ci                        Type::Ref(ty) => {
8033d722a9Sopenharmony_ci                            if ty.mutable && !ty.pinned {
8133d722a9Sopenharmony_ci                                if let Type::Ident(ident) = &ty.inner {
8233d722a9Sopenharmony_ci                                    let reason = TrivialReason::UnpinnedMut(efn);
8333d722a9Sopenharmony_ci                                    insist_extern_types_are_trivial(ident, reason);
8433d722a9Sopenharmony_ci                                }
8533d722a9Sopenharmony_ci                            }
8633d722a9Sopenharmony_ci                        }
8733d722a9Sopenharmony_ci                        _ => {}
8833d722a9Sopenharmony_ci                    }
8933d722a9Sopenharmony_ci                }
9033d722a9Sopenharmony_ci            }
9133d722a9Sopenharmony_ci            _ => {}
9233d722a9Sopenharmony_ci        }
9333d722a9Sopenharmony_ci    }
9433d722a9Sopenharmony_ci
9533d722a9Sopenharmony_ci    for ty in all {
9633d722a9Sopenharmony_ci        match ty {
9733d722a9Sopenharmony_ci            Type::RustBox(ty) => {
9833d722a9Sopenharmony_ci                if let Type::Ident(ident) = &ty.inner {
9933d722a9Sopenharmony_ci                    let reason = TrivialReason::BoxTarget;
10033d722a9Sopenharmony_ci                    insist_extern_types_are_trivial(ident, reason);
10133d722a9Sopenharmony_ci                }
10233d722a9Sopenharmony_ci            }
10333d722a9Sopenharmony_ci            Type::RustVec(ty) => {
10433d722a9Sopenharmony_ci                if let Type::Ident(ident) = &ty.inner {
10533d722a9Sopenharmony_ci                    let reason = TrivialReason::VecElement;
10633d722a9Sopenharmony_ci                    insist_extern_types_are_trivial(ident, reason);
10733d722a9Sopenharmony_ci                }
10833d722a9Sopenharmony_ci            }
10933d722a9Sopenharmony_ci            Type::SliceRef(ty) => {
11033d722a9Sopenharmony_ci                if let Type::Ident(ident) = &ty.inner {
11133d722a9Sopenharmony_ci                    let reason = TrivialReason::SliceElement {
11233d722a9Sopenharmony_ci                        mutable: ty.mutable,
11333d722a9Sopenharmony_ci                    };
11433d722a9Sopenharmony_ci                    insist_extern_types_are_trivial(ident, reason);
11533d722a9Sopenharmony_ci                }
11633d722a9Sopenharmony_ci            }
11733d722a9Sopenharmony_ci            _ => {}
11833d722a9Sopenharmony_ci        }
11933d722a9Sopenharmony_ci    }
12033d722a9Sopenharmony_ci
12133d722a9Sopenharmony_ci    required_trivial
12233d722a9Sopenharmony_ci}
12333d722a9Sopenharmony_ci
12433d722a9Sopenharmony_ci// Context:
12533d722a9Sopenharmony_ci// "type {type} should be trivially move constructible and trivially destructible in C++ to be used as {what} in Rust"
12633d722a9Sopenharmony_ci// "needs a cxx::ExternType impl in order to be used as {what}"
12733d722a9Sopenharmony_cipub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display + 'a {
12833d722a9Sopenharmony_ci    struct Description<'a> {
12933d722a9Sopenharmony_ci        name: &'a Pair,
13033d722a9Sopenharmony_ci        reasons: &'a [TrivialReason<'a>],
13133d722a9Sopenharmony_ci    }
13233d722a9Sopenharmony_ci
13333d722a9Sopenharmony_ci    impl<'a> Display for Description<'a> {
13433d722a9Sopenharmony_ci        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
13533d722a9Sopenharmony_ci            let mut field_of = Set::new();
13633d722a9Sopenharmony_ci            let mut argument_of = Set::new();
13733d722a9Sopenharmony_ci            let mut return_of = Set::new();
13833d722a9Sopenharmony_ci            let mut box_target = false;
13933d722a9Sopenharmony_ci            let mut vec_element = false;
14033d722a9Sopenharmony_ci            let mut slice_shared_element = false;
14133d722a9Sopenharmony_ci            let mut slice_mut_element = false;
14233d722a9Sopenharmony_ci            let mut unpinned_mut = Set::new();
14333d722a9Sopenharmony_ci
14433d722a9Sopenharmony_ci            for reason in self.reasons {
14533d722a9Sopenharmony_ci                match reason {
14633d722a9Sopenharmony_ci                    TrivialReason::StructField(strct) => {
14733d722a9Sopenharmony_ci                        field_of.insert(&strct.name.rust);
14833d722a9Sopenharmony_ci                    }
14933d722a9Sopenharmony_ci                    TrivialReason::FunctionArgument(efn) => {
15033d722a9Sopenharmony_ci                        argument_of.insert(&efn.name.rust);
15133d722a9Sopenharmony_ci                    }
15233d722a9Sopenharmony_ci                    TrivialReason::FunctionReturn(efn) => {
15333d722a9Sopenharmony_ci                        return_of.insert(&efn.name.rust);
15433d722a9Sopenharmony_ci                    }
15533d722a9Sopenharmony_ci                    TrivialReason::BoxTarget => box_target = true,
15633d722a9Sopenharmony_ci                    TrivialReason::VecElement => vec_element = true,
15733d722a9Sopenharmony_ci                    TrivialReason::SliceElement { mutable } => {
15833d722a9Sopenharmony_ci                        if *mutable {
15933d722a9Sopenharmony_ci                            slice_mut_element = true;
16033d722a9Sopenharmony_ci                        } else {
16133d722a9Sopenharmony_ci                            slice_shared_element = true;
16233d722a9Sopenharmony_ci                        }
16333d722a9Sopenharmony_ci                    }
16433d722a9Sopenharmony_ci                    TrivialReason::UnpinnedMut(efn) => {
16533d722a9Sopenharmony_ci                        unpinned_mut.insert(&efn.name.rust);
16633d722a9Sopenharmony_ci                    }
16733d722a9Sopenharmony_ci                }
16833d722a9Sopenharmony_ci            }
16933d722a9Sopenharmony_ci
17033d722a9Sopenharmony_ci            let mut clauses = Vec::new();
17133d722a9Sopenharmony_ci            if !field_of.is_empty() {
17233d722a9Sopenharmony_ci                clauses.push(Clause::Set {
17333d722a9Sopenharmony_ci                    article: "a",
17433d722a9Sopenharmony_ci                    desc: "field of",
17533d722a9Sopenharmony_ci                    set: &field_of,
17633d722a9Sopenharmony_ci                });
17733d722a9Sopenharmony_ci            }
17833d722a9Sopenharmony_ci            if !argument_of.is_empty() {
17933d722a9Sopenharmony_ci                clauses.push(Clause::Set {
18033d722a9Sopenharmony_ci                    article: "an",
18133d722a9Sopenharmony_ci                    desc: "argument of",
18233d722a9Sopenharmony_ci                    set: &argument_of,
18333d722a9Sopenharmony_ci                });
18433d722a9Sopenharmony_ci            }
18533d722a9Sopenharmony_ci            if !return_of.is_empty() {
18633d722a9Sopenharmony_ci                clauses.push(Clause::Set {
18733d722a9Sopenharmony_ci                    article: "a",
18833d722a9Sopenharmony_ci                    desc: "return value of",
18933d722a9Sopenharmony_ci                    set: &return_of,
19033d722a9Sopenharmony_ci                });
19133d722a9Sopenharmony_ci            }
19233d722a9Sopenharmony_ci            if box_target {
19333d722a9Sopenharmony_ci                clauses.push(Clause::Ty1 {
19433d722a9Sopenharmony_ci                    article: "type",
19533d722a9Sopenharmony_ci                    desc: "Box",
19633d722a9Sopenharmony_ci                    param: self.name,
19733d722a9Sopenharmony_ci                });
19833d722a9Sopenharmony_ci            }
19933d722a9Sopenharmony_ci            if vec_element {
20033d722a9Sopenharmony_ci                clauses.push(Clause::Ty1 {
20133d722a9Sopenharmony_ci                    article: "a",
20233d722a9Sopenharmony_ci                    desc: "vector element in Vec",
20333d722a9Sopenharmony_ci                    param: self.name,
20433d722a9Sopenharmony_ci                });
20533d722a9Sopenharmony_ci            }
20633d722a9Sopenharmony_ci            if slice_shared_element || slice_mut_element {
20733d722a9Sopenharmony_ci                clauses.push(Clause::Slice {
20833d722a9Sopenharmony_ci                    article: "a",
20933d722a9Sopenharmony_ci                    desc: "slice element in",
21033d722a9Sopenharmony_ci                    shared: slice_shared_element,
21133d722a9Sopenharmony_ci                    mutable: slice_mut_element,
21233d722a9Sopenharmony_ci                    param: self.name,
21333d722a9Sopenharmony_ci                });
21433d722a9Sopenharmony_ci            }
21533d722a9Sopenharmony_ci            if !unpinned_mut.is_empty() {
21633d722a9Sopenharmony_ci                clauses.push(Clause::Set {
21733d722a9Sopenharmony_ci                    article: "a",
21833d722a9Sopenharmony_ci                    desc: "non-pinned mutable reference in signature of",
21933d722a9Sopenharmony_ci                    set: &unpinned_mut,
22033d722a9Sopenharmony_ci                });
22133d722a9Sopenharmony_ci            }
22233d722a9Sopenharmony_ci
22333d722a9Sopenharmony_ci            for (i, clause) in clauses.iter().enumerate() {
22433d722a9Sopenharmony_ci                if i == 0 {
22533d722a9Sopenharmony_ci                    write!(f, "{} ", clause.article())?;
22633d722a9Sopenharmony_ci                } else if i + 1 < clauses.len() {
22733d722a9Sopenharmony_ci                    write!(f, ", ")?;
22833d722a9Sopenharmony_ci                } else {
22933d722a9Sopenharmony_ci                    write!(f, " or ")?;
23033d722a9Sopenharmony_ci                }
23133d722a9Sopenharmony_ci                clause.fmt(f)?;
23233d722a9Sopenharmony_ci            }
23333d722a9Sopenharmony_ci
23433d722a9Sopenharmony_ci            Ok(())
23533d722a9Sopenharmony_ci        }
23633d722a9Sopenharmony_ci    }
23733d722a9Sopenharmony_ci
23833d722a9Sopenharmony_ci    enum Clause<'a> {
23933d722a9Sopenharmony_ci        Set {
24033d722a9Sopenharmony_ci            article: &'a str,
24133d722a9Sopenharmony_ci            desc: &'a str,
24233d722a9Sopenharmony_ci            set: &'a Set<&'a Ident>,
24333d722a9Sopenharmony_ci        },
24433d722a9Sopenharmony_ci        Ty1 {
24533d722a9Sopenharmony_ci            article: &'a str,
24633d722a9Sopenharmony_ci            desc: &'a str,
24733d722a9Sopenharmony_ci            param: &'a Pair,
24833d722a9Sopenharmony_ci        },
24933d722a9Sopenharmony_ci        Slice {
25033d722a9Sopenharmony_ci            article: &'a str,
25133d722a9Sopenharmony_ci            desc: &'a str,
25233d722a9Sopenharmony_ci            shared: bool,
25333d722a9Sopenharmony_ci            mutable: bool,
25433d722a9Sopenharmony_ci            param: &'a Pair,
25533d722a9Sopenharmony_ci        },
25633d722a9Sopenharmony_ci    }
25733d722a9Sopenharmony_ci
25833d722a9Sopenharmony_ci    impl<'a> Clause<'a> {
25933d722a9Sopenharmony_ci        fn article(&self) -> &'a str {
26033d722a9Sopenharmony_ci            match self {
26133d722a9Sopenharmony_ci                Clause::Set { article, .. }
26233d722a9Sopenharmony_ci                | Clause::Ty1 { article, .. }
26333d722a9Sopenharmony_ci                | Clause::Slice { article, .. } => article,
26433d722a9Sopenharmony_ci            }
26533d722a9Sopenharmony_ci        }
26633d722a9Sopenharmony_ci
26733d722a9Sopenharmony_ci        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26833d722a9Sopenharmony_ci            match self {
26933d722a9Sopenharmony_ci                Clause::Set {
27033d722a9Sopenharmony_ci                    article: _,
27133d722a9Sopenharmony_ci                    desc,
27233d722a9Sopenharmony_ci                    set,
27333d722a9Sopenharmony_ci                } => {
27433d722a9Sopenharmony_ci                    write!(f, "{} ", desc)?;
27533d722a9Sopenharmony_ci                    for (i, ident) in set.iter().take(3).enumerate() {
27633d722a9Sopenharmony_ci                        if i > 0 {
27733d722a9Sopenharmony_ci                            write!(f, ", ")?;
27833d722a9Sopenharmony_ci                        }
27933d722a9Sopenharmony_ci                        write!(f, "`{}`", ident)?;
28033d722a9Sopenharmony_ci                    }
28133d722a9Sopenharmony_ci                    Ok(())
28233d722a9Sopenharmony_ci                }
28333d722a9Sopenharmony_ci                Clause::Ty1 {
28433d722a9Sopenharmony_ci                    article: _,
28533d722a9Sopenharmony_ci                    desc,
28633d722a9Sopenharmony_ci                    param,
28733d722a9Sopenharmony_ci                } => write!(f, "{}<{}>", desc, param.rust),
28833d722a9Sopenharmony_ci                Clause::Slice {
28933d722a9Sopenharmony_ci                    article: _,
29033d722a9Sopenharmony_ci                    desc,
29133d722a9Sopenharmony_ci                    shared,
29233d722a9Sopenharmony_ci                    mutable,
29333d722a9Sopenharmony_ci                    param,
29433d722a9Sopenharmony_ci                } => {
29533d722a9Sopenharmony_ci                    write!(f, "{} ", desc)?;
29633d722a9Sopenharmony_ci                    if *shared {
29733d722a9Sopenharmony_ci                        write!(f, "&[{}]", param.rust)?;
29833d722a9Sopenharmony_ci                    }
29933d722a9Sopenharmony_ci                    if *shared && *mutable {
30033d722a9Sopenharmony_ci                        write!(f, " and ")?;
30133d722a9Sopenharmony_ci                    }
30233d722a9Sopenharmony_ci                    if *mutable {
30333d722a9Sopenharmony_ci                        write!(f, "&mut [{}]", param.rust)?;
30433d722a9Sopenharmony_ci                    }
30533d722a9Sopenharmony_ci                    Ok(())
30633d722a9Sopenharmony_ci                }
30733d722a9Sopenharmony_ci            }
30833d722a9Sopenharmony_ci        }
30933d722a9Sopenharmony_ci    }
31033d722a9Sopenharmony_ci
31133d722a9Sopenharmony_ci    Description { name, reasons }
31233d722a9Sopenharmony_ci}
313