diff --git a/Cargo.lock b/Cargo.lock index 5bc06710..76b40187 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4138,7 +4138,7 @@ dependencies = [ [[package]] name = "playdate-bindgen" -version = "0.2.1" +version = "0.2.2" dependencies = [ "bindgen", "clap", @@ -4158,7 +4158,7 @@ dependencies = [ [[package]] name = "playdate-bindgen-cfg" -version = "0.2.0" +version = "0.2.1" dependencies = [ "clap", ] diff --git a/support/bindgen-cfg/Cargo.toml b/support/bindgen-cfg/Cargo.toml index 1da07004..034cdb44 100644 --- a/support/bindgen-cfg/Cargo.toml +++ b/support/bindgen-cfg/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-bindgen-cfg" -version = "0.2.0" +version = "0.2.1" readme = "README.md" description = "Minimal configuration for playdate-bindgen." keywords = ["playdate", "bindings", "ffi", "code-generation"] diff --git a/support/bindgen-cfg/src/lib.rs b/support/bindgen-cfg/src/lib.rs index da1df303..74e45daf 100644 --- a/support/bindgen-cfg/src/lib.rs +++ b/support/bindgen-cfg/src/lib.rs @@ -408,17 +408,17 @@ impl Filename { if !s.starts_with(Self::PREFIX.as_bytes()) || !s.ends_with(Self::DOT_EXT.as_bytes()) { None } else { - let from_encoded_bytes = std::ffi::OsStr::from_encoded_bytes_unchecked; + use std::ffi::OsStr; if let Some(target) = target { - let s = unsafe { from_encoded_bytes(&s[Self::PREFIX.len()..]) }; + let s = unsafe { OsStr::from_encoded_bytes_unchecked(&s[Self::PREFIX.len()..]) }; s.to_string_lossy() .split_once(target) .and_then(|(version, _)| version.get(..(version.len() - 1))) .map(OsString::from) .map(Cow::Owned) } else if let Some((prefix, _)) = &s[Self::PREFIX.len()..].split_once(|c| *c == b'-') { - let os = unsafe { from_encoded_bytes(prefix) }; + let os = unsafe { OsStr::from_encoded_bytes_unchecked(prefix) }; Some(os.into()) } else { None diff --git a/support/bindgen-cfg/src/mask.rs b/support/bindgen-cfg/src/mask.rs index 631a838f..217fbbb6 100644 --- a/support/bindgen-cfg/src/mask.rs +++ b/support/bindgen-cfg/src/mask.rs @@ -3,11 +3,11 @@ use crate::Derive; #[derive(Debug, Clone)] pub struct DerivesMask { - inner: Vec, + values: Vec, } impl DerivesMask { - pub fn push(&mut self, value: bool) { self.inner.push(value) } + pub fn push(&mut self, value: bool) { self.values.push(value) } pub fn from_ascii(mask: &[u8]) -> Result { @@ -19,7 +19,7 @@ impl DerivesMask { _ => return Err(ParseMaskError), } } - Ok(Self { inner: values }) + Ok(Self { values }) } pub fn from_str(mask: &str) -> Result { @@ -39,16 +39,16 @@ impl Default for DerivesMask { impl From for DerivesMask { fn from(values: Derive) -> Self { // Caution: do not change the order of items! - Self { inner: vec![ - values.default, - values.eq, - values.copy, - values.debug, - values.hash, - values.ord, - values.partialeq, - values.partialord, - values.constparamty, + Self { values: vec![ + values.default, + values.eq, + values.copy, + values.debug, + values.hash, + values.ord, + values.partialeq, + values.partialord, + values.constparamty, ] } } } @@ -59,28 +59,28 @@ impl From<&'_ Derive> for DerivesMask { impl std::fmt::Display for DerivesMask { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let iter = self.inner.iter().map(|v| if *v { "1" } else { "0" }); + let iter = self.values.iter().map(|v| if *v { "1" } else { "0" }); write!(f, "{}", iter.collect::()) } } impl PartialEq for DerivesMask { - fn eq(&self, other: &Self) -> bool { self.inner == other.inner } + fn eq(&self, other: &Self) -> bool { self.values == other.values } } impl PartialOrd for DerivesMask { fn partial_cmp(&self, other: &Self) -> Option { - if other.inner.len() > self.inner.len() && other.inner[self.inner.len()..].contains(&true) { + if other.values.len() > self.values.len() && other.values[self.values.len()..].contains(&true) { return Some(std::cmp::Ordering::Less); } - let len = self.inner.len().min(other.inner.len()); - let a = &self.inner[..len]; - let b = &other.inner[..len]; + let len = self.values.len().min(other.values.len()); + let a = &self.values[..len]; + let b = &other.values[..len]; let res = if a == b { - if self.inner.len() > other.inner.len() && self.inner[other.inner.len()..].contains(&true) { + if self.values.len() > other.values.len() && self.values[other.values.len()..].contains(&true) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal @@ -100,28 +100,40 @@ impl DerivesMask { /// The cost of positive remainder of `other`. const REST_DISTANCE: isize = 100; - /// Calc distance between two masks. + /// Calc "distance" between two masks. /// /// __Non-commutative function.__ /// - /// If distance between `a` & `b` is gt then `0`, that means `a` doesn't covers `b`. + /// Here the name "distance" means mesure of "how enough `a` (not) covers `b`". + /// + /// Result is signed, so if "`a` covers `b`" result is `0 - n` where `n = a - b`. + /// If distance between `a` & `b` is gt then `0`, that means `a` doesn't covers `b`, so if `a > b` => `d < 0`. + /// + /// Actually it's almost same as `xor` (`a ^ b`), + /// e.g. `0b1000 ^ 0b1010 = 0b10` and the "distance" is `1` which means + /// "`b` has one feature uncovered by `a`". + /// /// - /// e.g. if `a > b` => `d < 0`, so /// - `100 d 000 = -1` /// - `100 d 111 = 2` /// - `100 d 1111 = >2` - /// - `1001 d 111 = >2` + /// - `1001 d 111 = 2` + /// + /// Various len: + /// - if `a = 10010` and `b = 100`, the remainder of `a` (10) is not contributes to the distance because b doesn't extend that far + /// and "`a` covers `b`", + /// - if `a = 100` and `b = 10010`, the remainder of `b` (10) __is__ contributes to the distance significantly. pub fn distance(&self, other: &Self) -> isize { if self == other { 0 } else { - let a = self.inner.as_slice(); - let b = other.inner.as_slice(); + let a = self.values.as_slice(); + let b = other.values.as_slice(); let prefix = { - let len = self.inner.len().min(other.inner.len()); - let a = &self.inner[..len]; - let b = &other.inner[..len]; + let len = self.values.len().min(other.values.len()); + let a = &self.values[..len]; + let b = &other.values[..len]; a.iter().zip(b).fold(0, |acc, (a, b)| { acc + match (a, b) { @@ -138,7 +150,7 @@ impl DerivesMask { } // We do not take into account the remainder of `a` because we do not consider the net (real) distance, // but the difference, meaning “by how much `a` covers `b`”. - // Otherwise it will be like that: + // Otherwise it could be like that: // else if a[b.len()..].contains(&true) { -Self::REST_DISTANCE } else { 0 @@ -161,20 +173,65 @@ mod tests { use super::*; + #[test] + fn fmt() { + let mut mask = DerivesMask::default(); + assert!(!mask.to_string().contains('1')); + + mask.values[0] = true; + assert_eq!("100000000", &mask.to_string()); + + mask.values.fill(true); + assert_eq!("111111111", &mask.to_string()); + } + + + #[test] + fn err() { + assert!(DerivesMask::from_str("123456789").is_err()); + assert!(DerivesMask::from_str("-").is_err()); + assert!(DerivesMask::from_str("xyz").is_err()); + } + + #[test] + fn from_str() { + let empty = DerivesMask::default(); + let full = DerivesMask::from_str("111111111").unwrap(); + assert_ne!(empty, full); + assert_eq!(empty, DerivesMask::from_str("000000000").unwrap()); + assert!(DerivesMask::from_str("001000000").unwrap().values[2]); + + assert!(DerivesMask::from_str("").unwrap().values.is_empty()); + assert_eq!(3, DerivesMask::from_str("111").unwrap().values.len()); + } + + #[test] + fn from_ascii() { + let empty = DerivesMask::default(); + let full = DerivesMask::from_ascii(b"111111111").unwrap(); + assert_ne!(empty, full); + assert_eq!(empty, DerivesMask::from_ascii(b"000000000").unwrap()); + assert!(DerivesMask::from_ascii(b"001000000").unwrap().values[2]); + + assert!(DerivesMask::from_ascii(b"").unwrap().values.is_empty()); + assert_eq!(3, DerivesMask::from_ascii(b"111").unwrap().values.len()); + } + + #[test] fn eq() { let mut a = DerivesMask::default(); let mut b = DerivesMask::default(); assert_eq!(a, b); - a.inner[0] = true; + a.values[0] = true; assert_ne!(a, b); - b.inner[0] = true; + b.values[0] = true; assert_eq!(a, b); - let last = b.inner.len() - 1; - b.inner[last] = true; + let last = b.values.len() - 1; + b.values[last] = true; assert_ne!(a, b); } @@ -186,7 +243,7 @@ mod tests { assert!(a >= b, "{a} >= {b}"); assert!(a <= b, "{a} <= {b}"); - a.inner[0] = true; + a.values[0] = true; assert!(a != b, "{a} != {b}"); assert!(a > b, "{a} > {b}"); assert!(a >= b, "{a} >= {b}"); @@ -194,18 +251,18 @@ mod tests { assert!(b <= a, "{b} <= {a}"); assert!(b < a, "{b} < {a}"); - b.inner[0] = true; + b.values[0] = true; assert!(a == b, "{a} == {b}"); assert!(a >= b, "{a} >= {b}"); assert!(a <= b, "{a} <= {b}"); - let last = b.inner.len() - 1; - b.inner[last] = true; + let last = b.values.len() - 1; + b.values[last] = true; assert!(a != b, "{a} != {b}"); assert!(a < b, "{a} < {b}"); assert!(a <= b, "{a} <= {b}"); - a.inner.fill(true); + a.values.fill(true); assert!(a != b, "{a} != {b}"); assert!(a > b, "{a} > {b}"); assert!(a >= b, "{a} >= {b}"); @@ -243,32 +300,32 @@ mod tests { assert_eq!(0, a.distance(&b)); assert_eq!(0, b.distance(&a)); - a.inner[0] = true; + a.values[0] = true; assert_eq!(-1, a.distance(&b)); - b.inner[0] = true; + b.values[0] = true; assert_eq!(0, a.distance(&b)); - let last = b.inner.len() - 1; - b.inner[last] = true; + let last = b.values.len() - 1; + b.values[last] = true; assert_eq!(1, a.distance(&b)); assert_eq!(-1, b.distance(&a)); b.push(true); assert_eq!(TAIL + 1, a.distance(&b)); - b.inner[0] = false; + b.values[0] = false; assert_eq!(TAIL, a.distance(&b)); - a.inner[last] = true; + a.values[last] = true; assert_eq!(TAIL - 1, a.distance(&b)); - a.inner[1] = true; + a.values[1] = true; assert_eq!(TAIL - 2, a.distance(&b)); // 1001 d 111: - let a = DerivesMask { inner: vec![true, false, false, true] }; - let b = DerivesMask { inner: vec![true, true, true] }; + let a = DerivesMask { values: vec![true, false, false, true] }; + let b = DerivesMask { values: vec![true, true, true] }; assert_eq!(2, a.distance(&b)); assert_eq!(TAIL - 2, b.distance(&a)); } diff --git a/support/bindgen/Cargo.toml b/support/bindgen/Cargo.toml index 3abfda81..d3110b32 100644 --- a/support/bindgen/Cargo.toml +++ b/support/bindgen/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "playdate-bindgen" -version = "0.2.1" +version = "0.2.2" readme = "README.md" -description = "Bindgen configuration for Playdate API and utils." +description = "Preconfigured Bindgen with extra codegen for Playdate C-API." keywords = ["playdate", "bindings", "ffi", "code-generation"] categories = ["development-tools::ffi", "development-tools::build-utils"] edition.workspace = true @@ -19,6 +19,7 @@ semver.workspace = true html2md = { version = "0.2.15", optional = true } html5ever = { version = "0.27.0", optional = true } markup5ever_rcdom = { version = "0.3.0", optional = true } + # doc-gen: proc-macro2 = { version = "1.0", optional = true } syn = { version = "2.0", optional = true } # +full, extra-traits, visit-mut diff --git a/support/bindgen/src/cfg.rs b/support/bindgen/src/cfg.rs deleted file mode 100644 index 78dc48ee..00000000 --- a/support/bindgen/src/cfg.rs +++ /dev/null @@ -1,31 +0,0 @@ -use utils::toolchain::gcc::ArmToolchain; -use utils::toolchain::sdk::Sdk; - - -pub struct Cfg { - pub sdk: Option, - pub gcc: Option, - - pub derive: Derive, -} - -impl Default for Cfg { - fn default() -> Self { - Self { sdk: None, - gcc: None, - derive: Default::default() } - } -} - - -#[derive(Debug, Default, Clone, Copy)] -pub struct Derive { - pub default: bool, - pub eq: bool, - pub copy: bool, - pub debug: bool, - pub hash: bool, - pub ord: bool, - pub partialeq: bool, - pub partialord: bool, -} diff --git a/support/bindgen/src/lib.rs b/support/bindgen/src/lib.rs index 25409c97..388cb34f 100644 --- a/support/bindgen/src/lib.rs +++ b/support/bindgen/src/lib.rs @@ -5,7 +5,6 @@ use std::env; use std::path::{Path, PathBuf}; use bindgen::callbacks::DeriveInfo; use bindgen::{EnumVariation, RustTarget, Builder, MacroTypeVariation}; -use cfg::Filename; use utils::consts::*; use utils::toolchain::gcc::{ArmToolchain, Gcc}; use utils::toolchain::sdk::Sdk; @@ -19,7 +18,7 @@ pub mod gen; type Result = std::result::Result; -pub const SDK_VER_SUPPORTED: &str = ">=2.0.0, <=3.0.0"; +pub const SDK_VER_SUPPORTED: &str = ">=2.1.0, <3.0.0"; /// Generated Rust bindings. @@ -74,7 +73,7 @@ pub struct Generator { pub gcc: ArmToolchain, /// Suggested filename for export bindings. - pub filename: Filename, + pub filename: cfg::Filename, /// Configured [`bindgen::Builder`]. pub builder: Builder, @@ -140,7 +139,7 @@ fn create_generator(cfg: cfg::Cfg) -> Result { builder = apply_target(builder, &cargo_target_triple, &gcc); - let filename = Filename::new(version.to_owned(), cfg.derive)?; + let filename = cfg::Filename::new(version.to_owned(), cfg.derive)?; Ok(Generator { sdk, gcc, @@ -156,7 +155,9 @@ fn check_sdk_version(version: &str) -> Result { is_version_matches(version) .map(|(ver, res, req)| { if res { - println!("cargo:warning=Playdate SDK version not tested. Supported version '{req}' does not matches current '{ver}'.") + const PKG: &str = env!("CARGO_PKG_NAME"); + const VER: &str = env!("CARGO_PKG_VERSION"); + println!("cargo:warning=Playdate SDK v{ver} may not be compatible with {PKG} v{VER} which hasn't been tested with it. Supported '{req}' does not matches current '{ver}'.") } ver }) @@ -454,18 +455,16 @@ mod tests { } #[test] - fn is_version_matches() { + fn version_matches() { use super::is_version_matches as check; let map = |(_, res, _)| res; assert!(check("0.0").map(map).is_err()); assert!(!check("0.0.0").map(map).unwrap()); - assert!(check("2.0.0").map(map).unwrap()); - assert!(check("2.6.0").map(map).unwrap()); + assert!(check("2.1.0").map(map).unwrap()); assert!(check("2.7.0").map(map).unwrap()); assert!(!check("2.7.0-beta.3").map(map).unwrap()); - assert!(check("3.0.0").map(map).unwrap()); assert!(!check("3.1.0").map(map).unwrap()); } }