X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=8063532e454b169d89dbb0be8b6c2e0283fd8d1c;hb=d25cffee0dfb879d827717d4d90a1b4d184eed0a;hp=b1224a96d8be657623d32bdc670f21f6c842c27c;hpb=f160848382e6a1bc43dc100d77b96c4b4ecb3beb;p=ldk-c-bindings diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index b1224a9..8063532 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -173,13 +173,13 @@ pub fn is_enum_opaque(e: &syn::ItemEnum) -> bool { /// concrete C container struct, etc). #[must_use] pub struct GenericTypes<'a, 'b> { - self_ty: Option<(String, &'a syn::Path)>, + self_ty: Option, parent: Option<&'b GenericTypes<'b, 'b>>, - typed_generics: HashMap<&'a syn::Ident, (String, Option<&'a syn::Path>)>, + typed_generics: HashMap<&'a syn::Ident, String>, default_generics: HashMap<&'a syn::Ident, (syn::Type, syn::Type)>, } impl<'a, 'p: 'a> GenericTypes<'a, 'p> { - pub fn new(self_ty: Option<(String, &'a syn::Path)>) -> Self { + pub fn new(self_ty: Option) -> Self { Self { self_ty, parent: None, typed_generics: HashMap::new(), default_generics: HashMap::new(), } } @@ -192,6 +192,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { /// Learn the generics in generics in the current context, given a TypeResolver. pub fn learn_generics<'b, 'c>(&mut self, generics: &'a syn::Generics, types: &'b TypeResolver<'a, 'c>) -> bool { + let mut new_typed_generics = HashMap::new(); // First learn simple generics... for generic in generics.params.iter() { match generic { @@ -205,14 +206,13 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { if path_matches_nongeneric(&trait_bound.path, &["core", "clone", "Clone"]) { continue; } assert_simple_bound(&trait_bound); - if let Some(mut path) = types.maybe_resolve_path(&trait_bound.path, None) { + if let Some(path) = types.maybe_resolve_path(&trait_bound.path, None) { if types.skip_path(&path) { continue; } if path == "Sized" { continue; } if non_lifetimes_processed { return false; } non_lifetimes_processed = true; - let new_ident = if path != "std::ops::Deref" && path != "core::ops::Deref" { - path = "crate::".to_string() + &path; - Some(&trait_bound.path) + if path != "std::ops::Deref" && path != "core::ops::Deref" { + new_typed_generics.insert(&type_param.ident, Some(path)); } else if trait_bound.path.segments.len() == 1 { // If we're templated on Deref, store // the reference type in `default_generics` which handles full @@ -231,11 +231,11 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { _ => unimplemented!(), } } - None - } else { None } - } else { None }; - self.typed_generics.insert(&type_param.ident, (path, new_ident)); - } else { return false; } + } else { + new_typed_generics.insert(&type_param.ident, None); + } + } + } } } if let Some(default) = type_param.default.as_ref() { @@ -254,9 +254,9 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { if p.qself.is_some() { return false; } if p.path.leading_colon.is_some() { return false; } let mut p_iter = p.path.segments.iter(); - if let Some(gen) = self.typed_generics.get_mut(&p_iter.next().unwrap().ident) { - if gen.0 != "std::ops::Deref" && gen.0 != "core::ops::Deref" { return false; } - if &format!("{}", p_iter.next().unwrap().ident) != "Target" { return false; } + if let Some(gen) = new_typed_generics.get_mut(&p_iter.next().unwrap().ident) { + if gen.is_some() { return false; } + if &format!("{}", p_iter.next().unwrap().ident) != "Target" {return false; } let mut non_lifetimes_processed = false; for bound in t.bounds.iter() { @@ -267,8 +267,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { if non_lifetimes_processed { return false; } non_lifetimes_processed = true; assert_simple_bound(&trait_bound); - *gen = ("crate::".to_string() + &types.resolve_path(&trait_bound.path, None), - Some(&trait_bound.path)); + *gen = Some(types.resolve_path(&trait_bound.path, None)); } } } else { return false; } @@ -276,8 +275,10 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { } } } - for (_, (_, ident)) in self.typed_generics.iter() { - if ident.is_none() { return false; } + for (key, value) in new_typed_generics.drain() { + if let Some(v) = value { + assert!(self.typed_generics.insert(key, v).is_none()); + } else { return false; } } true } @@ -292,17 +293,15 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { match bounds_iter.next().unwrap() { syn::TypeParamBound::Trait(tr) => { assert_simple_bound(&tr); - if let Some(mut path) = types.maybe_resolve_path(&tr.path, None) { + if let Some(path) = types.maybe_resolve_path(&tr.path, None) { if types.skip_path(&path) { continue; } // In general we handle Deref as if it were just X (and // implement Deref for relevant types). We don't // bother to implement it for associated types, however, so we just // ignore such bounds. - let new_ident = if path != "std::ops::Deref" && path != "core::ops::Deref" { - path = "crate::".to_string() + &path; - Some(&tr.path) - } else { None }; - self.typed_generics.insert(&t.ident, (path, new_ident)); + if path != "std::ops::Deref" && path != "core::ops::Deref" { + self.typed_generics.insert(&t.ident, path); + } } else { unimplemented!(); } }, _ => unimplemented!(), @@ -318,10 +317,10 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { pub fn maybe_resolve_ident<'b>(&'b self, ident: &syn::Ident) -> Option<&'b String> { if let Some(ty) = &self.self_ty { if format!("{}", ident) == "Self" { - return Some(&ty.0); + return Some(&ty); } } - if let Some(res) = self.typed_generics.get(ident).map(|(a, _)| a) { + if let Some(res) = self.typed_generics.get(ident) { return Some(res); } if let Some(parent) = self.parent { @@ -333,14 +332,14 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { /// Attempt to resolve a Path as a generic parameter and return the full path. as both a string /// and syn::Path. - pub fn maybe_resolve_path<'b>(&'b self, path: &syn::Path) -> Option<(&'b String, &'a syn::Path)> { + pub fn maybe_resolve_path<'b>(&'b self, path: &syn::Path) -> Option<&'b String> { if let Some(ident) = path.get_ident() { if let Some(ty) = &self.self_ty { if format!("{}", ident) == "Self" { - return Some((&ty.0, ty.1)); + return Some(&ty); } } - if let Some(res) = self.typed_generics.get(ident).map(|(a, b)| (a, b.unwrap())) { + if let Some(res) = self.typed_generics.get(ident) { return Some(res); } } else { @@ -349,7 +348,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { let mut it = path.segments.iter(); if path.segments.len() == 2 && format!("{}", it.next().unwrap().ident) == "Self" { let ident = &it.next().unwrap().ident; - if let Some(res) = self.typed_generics.get(ident).map(|(a, b)| (a, b.unwrap())) { + if let Some(res) = self.typed_generics.get(ident) { return Some(res); } } @@ -581,12 +580,12 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr } else { None } } - pub fn maybe_resolve_path(&self, p_arg: &syn::Path, generics: Option<&GenericTypes>) -> Option { - let p = if let Some(gen_types) = generics { - if let Some((_, synpath)) = gen_types.maybe_resolve_path(p_arg) { - synpath - } else { p_arg } - } else { p_arg }; + pub fn maybe_resolve_path(&self, p: &syn::Path, generics: Option<&GenericTypes>) -> Option { + if let Some(gen_types) = generics { + if let Some(resp) = gen_types.maybe_resolve_path(p) { + return Some(resp.clone()); + } + } if p.leading_colon.is_some() { let mut res: String = p.segments.iter().enumerate().map(|(idx, seg)| { @@ -889,6 +888,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "std::time::SystemTime" => Some("u64"), "std::io::Error" => Some("crate::c_types::IOError"), + "core::convert::Infallible" => Some("crate::c_types::NotConstructable"), + "bech32::u5" => Some("crate::c_types::u5"), "core::num::NonZeroU8" => Some("u8"), @@ -967,6 +968,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // Note that we'll panic for String if is_ref, as we only have non-owned memory, we // cannot create a &String. + "core::convert::Infallible" => Some("panic!(\"You must never construct a NotConstructable! : "), + "std::time::Duration"|"core::time::Duration" => Some("std::time::Duration::from_secs("), "std::time::SystemTime" => Some("(::std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs("), @@ -1045,6 +1048,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "alloc::string::String"|"String" => Some(".into_string()"), "std::io::Error" if !is_ref => Some(".to_rust()"), + "core::convert::Infallible" => Some("\")"), + "std::time::Duration"|"core::time::Duration" => Some(")"), "std::time::SystemTime" => Some("))"), @@ -1136,6 +1141,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "std::time::SystemTime" => Some(""), "std::io::Error" if !is_ref => Some("crate::c_types::IOError::from_rust("), + "core::convert::Infallible" => Some("panic!(\"Cannot construct an Infallible: "), + "bech32::u5" => Some(""), "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" @@ -1208,6 +1215,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "std::time::SystemTime" => Some(".duration_since(::std::time::SystemTime::UNIX_EPOCH).expect(\"Times must be post-1970\").as_secs()"), "std::io::Error" if !is_ref => Some(")"), + "core::convert::Infallible" => Some("\")"), + "bech32::u5" => Some(".into()"), "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" @@ -1261,6 +1270,18 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } } + /// When printing a reference to the source crate's rust type, if we need to map it to a + /// different "real" type, it can be done so here. + /// This is useful to work around limitations in the binding type resolver, where we reference + /// a non-public `use` alias. + /// TODO: We should never need to use this! + fn real_rust_type_mapping<'equiv>(&self, thing: &'equiv str) -> &'equiv str { + match thing { + "lightning::io::Read" => "std::io::Read", + _ => thing, + } + } + // **************************** // *** Container Processing *** // **************************** @@ -1557,7 +1578,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // If we're printing a generic argument, it needs to reference the crate, otherwise // the original crate: } else if self.maybe_resolve_path(&path, None).as_ref() == Some(&resolved) { - write!(w, "{}", resolved).unwrap(); + write!(w, "{}", self.real_rust_type_mapping(&resolved)).unwrap(); } else { write!(w, "crate::{}", resolved).unwrap(); }