1 // Copyright (c) Facebook, Inc. and its affiliates.
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
6 use arena_deserializer::serde::Deserialize;
7 use decl_provider::{self, DeclProvider};
8 use libc::{c_char, c_int};
9 use oxidized_by_ref::file_info::NameType;
10 use oxidized_by_ref::{direct_decl_parser, shallow_decl_defs::Decl};
13 Technically, the object layout of the values we are working with
14 (produced in C++) is this (c.f. 'rust_ffi_compile.rs' and
15 'hh_single_compile.cpp' (for example)):
17 struct Decls<'decl>(direct_decl_parser::Decls<'decl>);
18 struct Bytes(ffi::Bytes);
20 enum ExternalDeclProviderResult<'decl> {
22 Decls(*const Decls<'decl>),
26 That is, when C++ returns us results, this is formally the layout we
29 With that definition for `ExternalDeclProvider<'decl>` then, in the
30 `ExternalDeclProviderResult::Decls(p)` case you can get at the actual
33 let decls: &Decls<'decl> = &(unsafe { p.as_ref() }.unwrap().0);
36 This definition for `ExternalDeclProvider<'decl>` and that access
37 style naturally works. There is a simplification we can make though.
40 - a `*const Decls<'decl>` as a `*const direct_decl_parser::Decls<'decl>`
41 - a `*const Bytes` as a `*const ffi::Bytes`
42 (both points follow from the fact that the address of a POD is equal
43 to the address of its first member).
45 Therefore, we arrive at the equivalent but more direct
47 pub enum ExternalDeclProviderResult<'decl> {
49 Decls(*const direct_decls::Decls<'decl>),
50 Bytes(*const ffi::Bytes),
53 and, given a value of case `ExternalDeclProviderResult::Decls(p)`, go
54 straight to the decls with:
56 let decls: &Decls<'decl> = unsafe { p.as_ref() }.unwrap();
60 pub enum ExternalDeclProviderResult<'decl> {
62 Decls(*const direct_decl_parser::Decls<'decl>),
63 Bytes(*const ffi::Bytes),
67 pub struct ExternalDeclProvider<'decl>(
68 pub unsafe extern "C" fn(
69 *const std::ffi::c_void, // Caller provided cookie
70 c_int, // A proxy for `HPHP::AutoloadMap::KindOf`
71 *const c_char, // The symbol
72 ) -> ExternalDeclProviderResult<'decl>, // Possible payload: `*const Decl<'decl>` or, `const* Bytes`
73 pub *const std::ffi::c_void,
77 impl<'decl> DeclProvider<'decl> for ExternalDeclProvider<'decl> {
78 fn get_decl(&self, kind: NameType, symbol: &str) -> Result<Decl<'decl>, decl_provider::Error> {
79 // Need to convert NameType into HPHP::AutoloadMap::KindOf.
80 let code: i32 = match kind {
81 NameType::Class => 0, // HPHP::AutoloadMap::KindOf::Type
82 NameType::Typedef => 3, // HPHP::AutoloadMap::KindOf::TypeAlias
83 NameType::Fun => 1, // HPHP::AutoloadMap::KindOf::Function
84 NameType::Const => 2, // HPHP::AutoloadMap::KindOf::Constant
85 NameType::RecordDef => panic!("RecordDef is not a valid HPHP::AutoloadMap::KindOf"),
87 let symbol_ptr = std::ffi::CString::new(symbol).unwrap();
88 match unsafe { self.0(self.1, code, symbol_ptr.as_c_str().as_ptr()) } {
89 ExternalDeclProviderResult::Missing => Err(decl_provider::Error::NotFound),
90 ExternalDeclProviderResult::Decls(p) => {
91 let decls: &direct_decl_parser::Decls<'decl> = unsafe { p.as_ref() }.unwrap();
94 .find_map(|(sym, decl)| if sym == symbol { Some(decl) } else { None });
96 None => Err(decl_provider::Error::NotFound),
97 Some(decl) => Ok(decl),
100 ExternalDeclProviderResult::Bytes(p) => {
101 let bytes: &ffi::Bytes = unsafe { p.as_ref() }.unwrap();
103 let data = unsafe { std::slice::from_raw_parts(bytes.data, bytes.len) };
104 let op = bincode::config::Options::with_native_endian(bincode::options());
105 let mut de = bincode::de::Deserializer::from_slice(data, op);
107 let de = arena_deserializer::ArenaDeserializer::new(&arena, &mut de);
108 let decls = direct_decl_parser::Decls::deserialize(de)
109 .map_err(|e| format!("failed to deserialize, error: {}", e))
114 .find_map(|(sym, decl)| if sym == symbol { Some(decl) } else { None });
116 None => Err(decl_provider::Error::NotFound),
117 Some(decl) => Ok(decl),
122 } //impl<'decl> DeclProvider<'decl> for ExternalDeclProvider<'decl>
124 impl<'decl> ExternalDeclProvider<'decl> {
126 decl_getter: unsafe extern "C" fn(
127 *const std::ffi::c_void,
130 ) -> ExternalDeclProviderResult<'decl>,
131 decl_provider: *const std::ffi::c_void,
132 decl_allocator: &'decl bumpalo::Bump,
134 Self(decl_getter, decl_provider, decl_allocator)