From 457a65d6c374ce9c3156c6a1b7a036b0553aad95 Mon Sep 17 00:00:00 2001
From: Fabio Valentini <decathorpe@gmail.com>
Date: Fri, 28 Jul 2023 01:55:31 +0200
Subject: [PATCH] Fixes for using serde_derive on x86_64 without precompiled
 binaries

---
 ...ecompiled-binary-that-s-not-usable-f.patch | 268 ++++++++++++++++++
 rust-serde_derive.spec                        |   9 +-
 serde_derive-fix-metadata.diff                |  30 ++
 3 files changed, 306 insertions(+), 1 deletion(-)
 create mode 100644 0001-Drop-usage-of-precompiled-binary-that-s-not-usable-f.patch
 create mode 100644 serde_derive-fix-metadata.diff

diff --git a/0001-Drop-usage-of-precompiled-binary-that-s-not-usable-f.patch b/0001-Drop-usage-of-precompiled-binary-that-s-not-usable-f.patch
new file mode 100644
index 0000000..38c0220
--- /dev/null
+++ b/0001-Drop-usage-of-precompiled-binary-that-s-not-usable-f.patch
@@ -0,0 +1,268 @@
+From f9d8ac2bfeb49b147c14e06c67a35d06dfc53421 Mon Sep 17 00:00:00 2001
+From: Fabio Valentini <decathorpe@gmail.com>
+Date: Fri, 28 Jul 2023 01:34:22 +0200
+Subject: [PATCH] Drop usage of precompiled binary that's not usable for
+ package builds
+
+---
+ src/lib.rs             |   4 -
+ src/lib_precompiled.rs | 234 -----------------------------------------
+ 2 files changed, 238 deletions(-)
+ delete mode 100644 src/lib_precompiled.rs
+
+diff --git a/src/lib.rs b/src/lib.rs
+index 7023d2d..8d5945e 100644
+--- a/src/lib.rs
++++ b/src/lib.rs
+@@ -15,8 +15,4 @@
+ 
+ #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.177")]
+ 
+-#[cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))]
+ include!("lib_from_source.rs");
+-
+-#[cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))]
+-include!("lib_precompiled.rs");
+diff --git a/src/lib_precompiled.rs b/src/lib_precompiled.rs
+deleted file mode 100644
+index 40116a8..0000000
+--- a/src/lib_precompiled.rs
++++ /dev/null
+@@ -1,234 +0,0 @@
+-extern crate proc_macro;
+-
+-mod buffer;
+-mod bytecode;
+-
+-use crate::buffer::{InputBuffer, OutputBuffer};
+-use crate::bytecode::Bytecode;
+-use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
+-use std::io::{ErrorKind, Read, Write};
+-use std::iter::FromIterator;
+-use std::path::Path;
+-use std::process::{Command, ExitStatus, Stdio};
+-use std::str::FromStr;
+-
+-#[proc_macro_derive(Serialize, attributes(serde))]
+-pub fn derive_serialize(input: TokenStream) -> TokenStream {
+-    derive(0, input)
+-}
+-
+-#[proc_macro_derive(Deserialize, attributes(serde))]
+-pub fn derive_deserialize(input: TokenStream) -> TokenStream {
+-    derive(1 + cfg!(feature = "deserialize_in_place") as u8, input)
+-}
+-
+-fn derive(select: u8, input: TokenStream) -> TokenStream {
+-    let mut memory = TokenMemory::default();
+-    let mut buf = OutputBuffer::new();
+-    buf.write_u8(select);
+-
+-    memory.spans.push(Span::call_site());
+-    for token in input {
+-        memory.linearize_token(token, &mut buf);
+-    }
+-
+-    let exe_path = Path::new(concat!(
+-        env!("CARGO_MANIFEST_DIR"),
+-        "/serde_derive-x86_64-unknown-linux-gnu",
+-    ));
+-    let mut child = match Command::new(exe_path)
+-        .stdin(Stdio::piped())
+-        .stdout(Stdio::piped())
+-        .spawn()
+-    {
+-        Ok(child) => child,
+-        Err(io_error) => {
+-            if io_error.kind() == ErrorKind::NotFound {
+-                panic!(
+-                    "file missing from serde_derive manifest directory during macro expansion: {}",
+-                    exe_path.display(),
+-                );
+-            } else {
+-                panic!("failed to spawn process: {}", io_error);
+-            }
+-        }
+-    };
+-
+-    let mut stdin = child.stdin.take().unwrap();
+-    let mut buf = buf.into_bytes();
+-    stdin.write_all(&buf).unwrap();
+-    drop(stdin);
+-
+-    let mut stdout = child.stdout.take().unwrap();
+-    buf.clear();
+-    stdout.read_to_end(&mut buf).unwrap();
+-
+-    let success = child.wait().as_ref().map_or(true, ExitStatus::success);
+-    if !success || buf.is_empty() {
+-        panic!();
+-    }
+-
+-    let mut buf = InputBuffer::new(&buf);
+-    memory.receive(&mut buf)
+-}
+-
+-#[derive(Default)]
+-struct TokenMemory {
+-    spans: Vec<Span>,
+-    groups: Vec<Group>,
+-    idents: Vec<Ident>,
+-    puncts: Vec<Punct>,
+-    literals: Vec<Literal>,
+-}
+-
+-enum Kind {
+-    Group(Delimiter),
+-    Ident,
+-    Punct(Spacing),
+-    Literal,
+-}
+-
+-impl TokenMemory {
+-    // Depth-first post-order traversal.
+-    fn linearize_token(&mut self, token: TokenTree, buf: &mut OutputBuffer) {
+-        match token {
+-            TokenTree::Group(group) => {
+-                let mut len = 0usize;
+-                for token in group.stream() {
+-                    self.linearize_token(token, buf);
+-                    len += 1;
+-                }
+-                assert!(len <= u32::MAX as usize);
+-                buf.write_u8(match group.delimiter() {
+-                    Delimiter::Parenthesis => Bytecode::GROUP_PARENTHESIS,
+-                    Delimiter::Brace => Bytecode::GROUP_BRACE,
+-                    Delimiter::Bracket => Bytecode::GROUP_BRACKET,
+-                    Delimiter::None => Bytecode::GROUP_NONE,
+-                });
+-                buf.write_u32(len as u32);
+-                self.spans
+-                    .extend([group.span(), group.span_open(), group.span_close()]);
+-                self.groups.push(group);
+-            }
+-            TokenTree::Ident(ident) => {
+-                buf.write_u8(Bytecode::IDENT);
+-                let repr = ident.to_string();
+-                assert!(repr.len() <= u16::MAX as usize);
+-                buf.write_u16(repr.len() as u16);
+-                buf.write_str(&repr);
+-                self.spans.push(ident.span());
+-                self.idents.push(ident);
+-            }
+-            TokenTree::Punct(punct) => {
+-                buf.write_u8(match punct.spacing() {
+-                    Spacing::Alone => Bytecode::PUNCT_ALONE,
+-                    Spacing::Joint => Bytecode::PUNCT_JOINT,
+-                });
+-                let ch = punct.as_char();
+-                assert!(ch.is_ascii());
+-                buf.write_u8(ch as u8);
+-                self.spans.push(punct.span());
+-                self.puncts.push(punct);
+-            }
+-            TokenTree::Literal(literal) => {
+-                buf.write_u8(Bytecode::LITERAL);
+-                let repr = literal.to_string();
+-                assert!(repr.len() <= u16::MAX as usize);
+-                buf.write_u16(repr.len() as u16);
+-                buf.write_str(&repr);
+-                self.spans.push(literal.span());
+-                self.literals.push(literal);
+-            }
+-        }
+-    }
+-
+-    fn receive(&self, buf: &mut InputBuffer) -> TokenStream {
+-        let mut trees = Vec::new();
+-        while !buf.is_empty() {
+-            match match buf.read_u8() {
+-                Bytecode::GROUP_PARENTHESIS => Kind::Group(Delimiter::Parenthesis),
+-                Bytecode::GROUP_BRACE => Kind::Group(Delimiter::Brace),
+-                Bytecode::GROUP_BRACKET => Kind::Group(Delimiter::Bracket),
+-                Bytecode::GROUP_NONE => Kind::Group(Delimiter::None),
+-                Bytecode::IDENT => Kind::Ident,
+-                Bytecode::PUNCT_ALONE => Kind::Punct(Spacing::Alone),
+-                Bytecode::PUNCT_JOINT => Kind::Punct(Spacing::Joint),
+-                Bytecode::LITERAL => Kind::Literal,
+-                Bytecode::LOAD_GROUP => {
+-                    let identity = buf.read_u32();
+-                    let group = self.groups[identity as usize].clone();
+-                    trees.push(TokenTree::Group(group));
+-                    continue;
+-                }
+-                Bytecode::LOAD_IDENT => {
+-                    let identity = buf.read_u32();
+-                    let ident = self.idents[identity as usize].clone();
+-                    trees.push(TokenTree::Ident(ident));
+-                    continue;
+-                }
+-                Bytecode::LOAD_PUNCT => {
+-                    let identity = buf.read_u32();
+-                    let punct = self.puncts[identity as usize].clone();
+-                    trees.push(TokenTree::Punct(punct));
+-                    continue;
+-                }
+-                Bytecode::LOAD_LITERAL => {
+-                    let identity = buf.read_u32();
+-                    let literal = self.literals[identity as usize].clone();
+-                    trees.push(TokenTree::Literal(literal));
+-                    continue;
+-                }
+-                Bytecode::SET_SPAN => {
+-                    trees.last_mut().unwrap().set_span(self.read_span(buf));
+-                    continue;
+-                }
+-                _ => unreachable!(),
+-            } {
+-                Kind::Group(delimiter) => {
+-                    let len = buf.read_u32();
+-                    let stream = trees.drain(trees.len() - len as usize..).collect();
+-                    let group = Group::new(delimiter, stream);
+-                    trees.push(TokenTree::Group(group));
+-                }
+-                Kind::Ident => {
+-                    let len = buf.read_u16();
+-                    let repr = buf.read_str(len as usize);
+-                    let span = self.read_span(buf);
+-                    let ident = if let Some(repr) = repr.strip_prefix("r#") {
+-                        Ident::new_raw(repr, span)
+-                    } else {
+-                        Ident::new(repr, span)
+-                    };
+-                    trees.push(TokenTree::Ident(ident));
+-                }
+-                Kind::Punct(spacing) => {
+-                    let ch = buf.read_u8();
+-                    assert!(ch.is_ascii());
+-                    let punct = Punct::new(ch as char, spacing);
+-                    trees.push(TokenTree::Punct(punct));
+-                }
+-                Kind::Literal => {
+-                    let len = buf.read_u16();
+-                    let repr = buf.read_str(len as usize);
+-                    let literal = Literal::from_str(repr).unwrap();
+-                    trees.push(TokenTree::Literal(literal));
+-                }
+-            }
+-        }
+-
+-        TokenStream::from_iter(trees)
+-    }
+-
+-    fn read_span(&self, buf: &mut InputBuffer) -> Span {
+-        let lo = buf.read_u32();
+-        let hi = buf.read_u32();
+-        let span = self.spans[lo as usize];
+-        if lo == hi {
+-            span
+-        } else {
+-            #[cfg(any())] // FIXME
+-            return span.join(self.spans[hi as usize]).unwrap_or(span);
+-            span
+-        }
+-    }
+-}
+-- 
+2.41.0
+
diff --git a/rust-serde_derive.spec b/rust-serde_derive.spec
index 0929f8a..542fb6c 100644
--- a/rust-serde_derive.spec
+++ b/rust-serde_derive.spec
@@ -13,6 +13,13 @@ Summary:        Implementation of #[derive(Serialize, Deserialize)]
 License:        MIT OR Apache-2.0
 URL:            https://crates.io/crates/serde_derive
 Source:         %{crates_source}
+# Manually created patch for downstream crate metadata changes
+# * ensure dependencies are available on all architectures
+Patch:          serde_derive-fix-metadata.diff
+
+# * do not rely on precompiled binaries on x86_64:
+#   https://github.com/serde-rs/serde/issues/2538
+Patch:          0001-Drop-usage-of-precompiled-binary-that-s-not-usable-f.patch
 
 BuildRequires:  rust-packaging >= 21
 
@@ -63,7 +70,7 @@ use the "deserialize_in_place" feature of the "%{crate}" crate.
 %prep
 %autosetup -n %{crate}-%{version_no_tilde} -p1
 %cargo_prep
-# remove pre-built binaries that are only used by an experimental feature
+# remove pre-built upstream binaries for x86_64 that MUST NOT be redistributed
 rm -v serde_derive-x86_64-unknown-linux-gnu
 
 %generate_buildrequires
diff --git a/serde_derive-fix-metadata.diff b/serde_derive-fix-metadata.diff
new file mode 100644
index 0000000..2f45a1c
--- /dev/null
+++ b/serde_derive-fix-metadata.diff
@@ -0,0 +1,30 @@
+--- serde_derive-1.0.177/Cargo.toml	1970-01-01T00:00:01+00:00
++++ serde_derive-1.0.177/Cargo.toml	2023-07-27T23:42:25.563651+00:00
+@@ -45,18 +45,18 @@
+ [lib]
+ proc-macro = true
+ 
++[dependencies.proc-macro2]
++version = "1"
++
++[dependencies.quote]
++version = "1"
++
++[dependencies.syn]
++version = "2.0.25"
++
+ [dev-dependencies.serde]
+ version = "1"
+ 
+ [features]
+ default = []
+ deserialize_in_place = []
+-
+-[target."cfg(not(all(target_arch = \"x86_64\", target_os = \"linux\", target_env = \"gnu\")))".dependencies.proc-macro2]
+-version = "1"
+-
+-[target."cfg(not(all(target_arch = \"x86_64\", target_os = \"linux\", target_env = \"gnu\")))".dependencies.quote]
+-version = "1"
+-
+-[target."cfg(not(all(target_arch = \"x86_64\", target_os = \"linux\", target_env = \"gnu\")))".dependencies.syn]
+-version = "2.0.25"