summaryrefslogtreecommitdiffstats
path: root/third_party/rust/serde_with_macros
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/serde_with_macros
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/serde_with_macros')
-rw-r--r--third_party/rust/serde_with_macros/.cargo-checksum.json1
-rw-r--r--third_party/rust/serde_with_macros/CHANGELOG.md33
-rw-r--r--third_party/rust/serde_with_macros/Cargo.toml65
-rw-r--r--third_party/rust/serde_with_macros/LICENSE-APACHE201
-rw-r--r--third_party/rust/serde_with_macros/LICENSE-MIT25
-rw-r--r--third_party/rust/serde_with_macros/README.md80
-rw-r--r--third_party/rust/serde_with_macros/src/lib.rs282
-rw-r--r--third_party/rust/serde_with_macros/tests/compile-fail/skip-none-always.rs30
-rw-r--r--third_party/rust/serde_with_macros/tests/compile-fail/skip-none-always.stderr17
-rw-r--r--third_party/rust/serde_with_macros/tests/compile-fail/skip-none-not-struct.rs8
-rw-r--r--third_party/rust/serde_with_macros/tests/compile-fail/skip-none-not-struct.stderr5
-rw-r--r--third_party/rust/serde_with_macros/tests/compiler-messages.rs15
-rw-r--r--third_party/rust/serde_with_macros/tests/skip_serializing_null.rs154
-rw-r--r--third_party/rust/serde_with_macros/tests/version_numbers.rs6
14 files changed, 922 insertions, 0 deletions
diff --git a/third_party/rust/serde_with_macros/.cargo-checksum.json b/third_party/rust/serde_with_macros/.cargo-checksum.json
new file mode 100644
index 0000000000..ae7af88657
--- /dev/null
+++ b/third_party/rust/serde_with_macros/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"5c5566da5a308015cfd18afd2d9db716601fd35a8b241beeedf10bb334f5ded4","Cargo.toml":"a5f76263232aa33cd38d1316ab6eb8a764ffd101a7277941330a827ccbcd820b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README.md":"dc4c1547049c0d11d544b1347aa67f4d947d761842c373729c2014dbb337e70b","src/lib.rs":"873adbaee30f72ee9c083c57711bbb1256d99fb6fdbe5e45c10e162861dca840","tests/compile-fail/skip-none-always.rs":"cdea0e110bc808f81c61d2ceb1394955b3af2be06261a85904e0e00a1948ff64","tests/compile-fail/skip-none-always.stderr":"cce5c9407f21b0a3eb880fb24cbb97a1e9ec22b21dcbd12963a745695175defd","tests/compile-fail/skip-none-not-struct.rs":"9212996740b302f2bd3b5298f439f8340c8cadddfb84212ddca975d5a78c4e12","tests/compile-fail/skip-none-not-struct.stderr":"0d1258fca42686eb120596c28d031935b1c22376954cebc858b0b7095d098e8e","tests/compiler-messages.rs":"06414ab54f1435839c79dcf649c577ec60c4c935a38967b1da989767c028f4e1","tests/skip_serializing_null.rs":"95c6c854d81f2b90e69455ae88f74b465919594920e34230374c9b8ceebfee77","tests/version_numbers.rs":"dccb4c715e3c4e6c08d9b779ad12122cded81becfde62fb54d2adf50171e5d83"},"package":"4070d2c9b9d258465ad1d82aabb985b84cd9a3afa94da25ece5a9938ba5f1606"} \ No newline at end of file
diff --git a/third_party/rust/serde_with_macros/CHANGELOG.md b/third_party/rust/serde_with_macros/CHANGELOG.md
new file mode 100644
index 0000000000..19b09478af
--- /dev/null
+++ b/third_party/rust/serde_with_macros/CHANGELOG.md
@@ -0,0 +1,33 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [1.1.0]
+
+### Changed
+
+* Bump minimal Rust version to 1.36.0 to support Rust Edition 2018
+* Improved CI pipeline by running `cargo audit` and `tarpaulin` in all configurations now.
+
+## [1.0.1]
+
+### Fixed
+
+* Features for the `syn` dependency were missing.
+ This was hidden due to the dev-dependencies whose features leaked into the normal build.
+
+## [1.0.0]
+
+Initial Release
+
+### Added
+
+* Add `skip_serializing_none` attribute, which adds `#[serde(skip_serializing_if = "Option::is_none")]` for each Option in a struct.
+ This is helpfull for APIs which have many optional fields.
+ The effect of can be negated by adding `serialize_always` on those fields, which should always be serialized.
+ Existing `skip_serializing_if` will never be modified and those fields keep their behavior.
diff --git a/third_party/rust/serde_with_macros/Cargo.toml b/third_party/rust/serde_with_macros/Cargo.toml
new file mode 100644
index 0000000000..ea8fd8dae5
--- /dev/null
+++ b/third_party/rust/serde_with_macros/Cargo.toml
@@ -0,0 +1,65 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "serde_with_macros"
+version = "1.1.0"
+authors = ["jonasbb"]
+description = "proc-macro library for serde_with"
+documentation = "https://docs.rs/serde_with_macros/"
+readme = "README.md"
+keywords = ["serde", "utilities", "serialization", "deserialization"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/jonasbb/serde_with/tree/master/serde_with_macros"
+[package.metadata.docs.rs]
+all-features = true
+
+[lib]
+proc-macro = true
+[dependencies.proc-macro2]
+version = "1.0.1"
+
+[dependencies.quote]
+version = "1.0.0"
+
+[dependencies.syn]
+version = "1.0.0"
+features = ["full"]
+[dev-dependencies.pretty_assertions]
+version = "0.6.1"
+
+[dev-dependencies.rustversion]
+version = "1.0.0"
+
+[dev-dependencies.serde]
+version = "1.0.75"
+features = ["derive"]
+
+[dev-dependencies.serde_json]
+version = "1.0.25"
+
+[dev-dependencies.trybuild]
+version = "1.0.14"
+
+[dev-dependencies.version-sync]
+version = "0.8.1"
+[badges.codecov]
+branch = "master"
+repository = "jonasbb/serde_with"
+service = "github"
+
+[badges.maintenance]
+status = "actively-developed"
+
+[badges.travis-ci]
+branch = "master"
+repository = "jonasbb/serde_with"
diff --git a/third_party/rust/serde_with_macros/LICENSE-APACHE b/third_party/rust/serde_with_macros/LICENSE-APACHE
new file mode 100644
index 0000000000..16fe87b06e
--- /dev/null
+++ b/third_party/rust/serde_with_macros/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust/serde_with_macros/LICENSE-MIT b/third_party/rust/serde_with_macros/LICENSE-MIT
new file mode 100644
index 0000000000..9203baa055
--- /dev/null
+++ b/third_party/rust/serde_with_macros/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2015
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/serde_with_macros/README.md b/third_party/rust/serde_with_macros/README.md
new file mode 100644
index 0000000000..ac02301fe9
--- /dev/null
+++ b/third_party/rust/serde_with_macros/README.md
@@ -0,0 +1,80 @@
+# Custom de/serialization functions for Rust's [serde](https://serde.rs)
+
+[![docs.rs badge](https://docs.rs/serde_with/badge.svg)](https://docs.rs/serde_with/)
+[![crates.io badge](https://img.shields.io/crates/v/serde_with.svg)](https://crates.io/crates/serde_with/)
+[![Build Status](https://travis-ci.org/jonasbb/serde_with.svg?branch=master)](https://travis-ci.org/jonasbb/serde_with)
+[![codecov](https://codecov.io/gh/jonasbb/serde_with/branch/master/graph/badge.svg)](https://codecov.io/gh/jonasbb/serde_with)
+
+---
+
+This crate provides custom de/serialization helpers to use in combination with [serde's with-annotation][with-annotation].
+
+Serde tracks a wishlist of similar helpers at [serde#553].
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies.serde_with]
+version = "1.4.0"
+features = [ "..." ]
+```
+
+The crate is divided into different modules.
+They contain helpers for external crates and must be enabled with the correspondig feature.
+
+Annotate your struct or enum to enable the custom de/serializer.
+
+```rust
+#[derive(Deserialize, Serialize)]
+struct Foo {
+ #[serde(with = "serde_with::rust::display_fromstr")]
+ bar: u8,
+}
+```
+
+Most helpers implement both deserialize and serialize.
+If you do not want to derive both, you can simply derive only the necessary parts.
+If you want to mix different helpers, you can write your annotations like
+
+```rust
+#[derive(Deserialize, Serialize)]
+struct Foo {
+ #[serde(
+ deserialize_with = "serde_with::rust::display_fromstr::deserialize",
+ serialize_with = "serde_with::json::nested::serialize"
+ )]
+ bar: u8,
+}
+```
+
+However, this will prohibit you from applying deserialize on the value returned by serializing a struct.
+
+## Attributes
+
+The crate comes with custom attributes, which futher extend how serde serialization can be customized.
+They are enabled by default, but can be disabled, by removing the default features from this crate.
+
+The `serde_with` crate re-exports all items from `serde_with_macros`.
+This means, if you want to use any proc_macros, import them like `use serde_with::skip_serializing_none`.
+
+[The documentation for the custom attributes can be found here.](serde_with_macros)
+
+[with-annotation]: https://serde.rs/field-attrs.html#serdewith--module
+[serde#553]: https://github.com/serde-rs/serde/issues/553
+
+## License
+
+Licensed under either of
+
+* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+at your option.
+
+## Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
diff --git a/third_party/rust/serde_with_macros/src/lib.rs b/third_party/rust/serde_with_macros/src/lib.rs
new file mode 100644
index 0000000000..3975aff6ff
--- /dev/null
+++ b/third_party/rust/serde_with_macros/src/lib.rs
@@ -0,0 +1,282 @@
+#![deny(
+ missing_debug_implementations,
+ missing_copy_implementations,
+ trivial_casts,
+ trivial_numeric_casts,
+ unused_extern_crates,
+ unused_import_braces,
+ unused_qualifications,
+ variant_size_differences
+)]
+#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
+#![doc(html_root_url = "https://docs.rs/serde_with_macros/1.1.0")]
+
+//! proc-macro extensions for [`serde_with`]
+//!
+//! This crate should not be used alone, but through the [`serde_with`] crate.
+//!
+//! [`serde_with`]: https://crates.io/crates/serde_with/
+
+extern crate proc_macro;
+extern crate proc_macro2;
+extern crate quote;
+extern crate syn;
+
+use proc_macro::TokenStream;
+use proc_macro2::Span;
+use quote::quote;
+use syn::{
+ parse::Parser, Attribute, Error, Field, Fields, ItemEnum, ItemStruct, Meta, NestedMeta, Path,
+ Type,
+};
+
+/// Add `skip_serializing_if` annotations to [`Option`] fields.
+///
+/// The attribute can be added to structs and enums.
+///
+/// Import this attribute with `use serde_with::skip_serializing_none;`.
+///
+/// # Example
+///
+/// JSON APIs sometimes have many optional values.
+/// Missing values should not be serialized, to keep the serialized format smaller.
+/// Such a data type might look like:
+///
+/// ```rust
+/// # extern crate serde;
+/// # use serde::Serialize;
+/// #
+/// #[derive(Serialize)]
+/// struct Data {
+/// #[serde(skip_serializing_if = "Option::is_none")]
+/// a: Option<String>,
+/// #[serde(skip_serializing_if = "Option::is_none")]
+/// b: Option<u64>,
+/// #[serde(skip_serializing_if = "Option::is_none")]
+/// c: Option<String>,
+/// #[serde(skip_serializing_if = "Option::is_none")]
+/// d: Option<bool>,
+/// }
+/// ```
+///
+/// The `skip_serializing_if` annotation is repetitive and harms readability.
+/// Instead the same struct can be written as:
+///
+/// ```rust
+/// # extern crate serde;
+/// # extern crate serde_with_macros;
+/// #
+/// # use serde::Serialize;
+/// # use serde_with_macros::skip_serializing_none;
+/// #[skip_serializing_none]
+/// #[derive(Serialize)]
+/// struct Data {
+/// a: Option<String>,
+/// b: Option<u64>,
+/// c: Option<String>,
+/// d: Option<bool>,
+/// }
+/// ```
+///
+/// Existing `skip_serializing_if` annotations will not be altered.
+///
+/// If some values should always be serialized, then the `serialize_always` can be used.
+///
+/// # Limitations
+///
+/// The `serialize_always` cannot be used together with a manual `skip_serializing_if` annotations, as these conflict in their meaning.
+/// A compile error will be generated if this occurs.
+///
+/// The `skip_serializing_none` only works if the type is called [`Option`], [`std::option::Option`], or [`core::option::Option`].
+/// Type aliasing an [`Option`] and giving it another name, will cause this field to be ignored.
+/// This cannot be supported, as proc-macros run before type checking, thus it is not possible to determine if a type alias refers to an [`Option`].
+///
+/// ```rust,ignore
+/// # extern crate serde;
+/// # extern crate serde_with_macros;
+/// #
+/// # use serde::Serialize;
+/// # use serde_with_macros::skip_serializing_none;
+/// type MyOption<T> = Option<T>;
+///
+/// #[skip_serializing_none]
+/// #[derive(Serialize)]
+/// struct Data {
+/// a: MyOption<String>, // This field will not be skipped
+/// }
+/// ```
+///
+/// Likewise, if you import a type and name it `Option`, the `skip_serializing_if` attributes will be added and compile errors will occur, if `Option::is_none` is not a valid function.
+/// Here the function `Vec::is_none` does not exist and therefore the example fails to compile.
+///
+/// ```rust,compile_fail
+/// # extern crate serde;
+/// # extern crate serde_with_macros;
+/// #
+/// # use serde::Serialize;
+/// # use serde_with_macros::skip_serializing_none;
+/// use std::vec::Vec as Option;
+///
+/// #[skip_serializing_none]
+/// #[derive(Serialize)]
+/// struct Data {
+/// a: Option<String>,
+/// }
+/// ```
+///
+#[proc_macro_attribute]
+pub fn skip_serializing_none(_args: TokenStream, input: TokenStream) -> TokenStream {
+ let res = match skip_serializing_none_do(input) {
+ Ok(res) => res,
+ Err(msg) => {
+ let span = Span::call_site();
+ Error::new(span, msg).to_compile_error()
+ }
+ };
+ TokenStream::from(res)
+}
+
+fn skip_serializing_none_do(input: TokenStream) -> Result<proc_macro2::TokenStream, String> {
+ // For each field in the struct given by `input`, add the `skip_serializing_if` attribute,
+ // if and only if, it is of type `Option`
+ if let Ok(mut input) = syn::parse::<ItemStruct>(input.clone()) {
+ skip_serializing_none_handle_fields(&mut input.fields)?;
+ Ok(quote!(#input))
+ } else if let Ok(mut input) = syn::parse::<ItemEnum>(input) {
+ input
+ .variants
+ .iter_mut()
+ .map(|variant| skip_serializing_none_handle_fields(&mut variant.fields))
+ .collect::<Result<(), _>>()?;
+ Ok(quote!(#input))
+ } else {
+ Err("The attribute can only be applied to struct or enum definitions.".into())
+ }
+}
+
+/// Return `true`, if the type path refers to `std::option::Option`
+///
+/// Accepts
+///
+/// * `Option`
+/// * `std::option::Option`, with or without leading `::`
+/// * `core::option::Option`, with or without leading `::`
+fn is_std_option(path: &Path) -> bool {
+ (path.leading_colon.is_none() && path.segments.len() == 1 && path.segments[0].ident == "Option")
+ || (path.segments.len() == 3
+ && (path.segments[0].ident == "std" || path.segments[0].ident == "core")
+ && path.segments[1].ident == "option"
+ && path.segments[2].ident == "Option")
+}
+
+/// Determine if the `field` has an attribute with given `namespace` and `name`
+///
+/// On the example of
+/// `#[serde(skip_serializing_if = "Option::is_none")]`
+//
+/// * `serde` is the outermost path, here namespace
+/// * it contains a Meta::List
+/// * which contains in another Meta a Meta::NameValue
+/// * with the name being `skip_serializing_if`
+#[cfg_attr(feature = "cargo-clippy", allow(cmp_owned))]
+fn field_has_attribute(field: &Field, namespace: &str, name: &str) -> bool {
+ // On the example of
+ // #[serde(skip_serializing_if = "Option::is_none")]
+ //
+ // `serde` is the outermost path, here namespace
+ // it contains a Meta::List
+ // which contains in another Meta a Meta::NameValue
+ // with the name being `skip_serializing_if`
+
+ for attr in &field.attrs {
+ if attr.path.is_ident(namespace) {
+ // Ignore non parsable attributes, as these are not important for us
+ if let Ok(expr) = attr.parse_meta() {
+ if let Meta::List(expr) = expr {
+ for expr in expr.nested {
+ if let NestedMeta::Meta(Meta::NameValue(expr)) = expr {
+ if let Some(ident) = expr.path.get_ident() {
+ if ident.to_string() == name {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ false
+}
+
+/// Add the skip_serializing_if annotation to each field of the struct
+fn skip_serializing_none_add_attr_to_field<'a>(
+ fields: impl IntoIterator<Item = &'a mut Field>,
+) -> Result<(), String> {
+ fields.into_iter().map(|field| ->Result<(), String> {
+ if let Type::Path(path) = &field.ty.clone() {
+ if is_std_option(&path.path) {
+ let has_skip_serializing_if =
+ field_has_attribute(&field, "serde", "skip_serializing_if");
+
+ // Remove the `serialize_always` attribute
+ let mut has_always_attr = false;
+ field.attrs.retain(|attr| {
+ let has_attr = attr.path.is_ident("serialize_always");
+ has_always_attr |= has_attr;
+ !has_attr
+ });
+
+ // Error on conflicting attributes
+ if has_always_attr && has_skip_serializing_if {
+ let mut msg = r#"The attributes `serialize_always` and `serde(skip_serializing_if = "...")` cannot be used on the same field"#.to_string();
+ if let Some(ident) = &field.ident {
+ msg += ": `";
+ msg += &ident.to_string();
+ msg += "`";
+ }
+ msg +=".";
+ return Err(msg);
+ }
+
+ // Do nothing if `skip_serializing_if` or `serialize_always` is already present
+ if has_skip_serializing_if || has_always_attr {
+ return Ok(());
+ }
+
+ // Add the `skip_serializing_if` attribute
+ let attr_tokens = quote!(
+ #[serde(skip_serializing_if = "Option::is_none")]
+ );
+ let parser = Attribute::parse_outer;
+ let attrs = parser
+ .parse2(attr_tokens)
+ .expect("Static attr tokens should not panic");
+ field.attrs.extend(attrs);
+ } else {
+ // Warn on use of `serialize_always` on non-Option fields
+ let has_attr= field.attrs.iter().any(|attr| {
+ attr.path.is_ident("serialize_always")
+ });
+ if has_attr {
+ return Err("`serialize_always` may only be used on fields of type `Option`.".into());
+ }
+ }
+ }
+ Ok(())
+ }).collect()
+}
+
+/// Handle a single struct or a single enum variant
+fn skip_serializing_none_handle_fields(fields: &mut Fields) -> Result<(), String> {
+ match fields {
+ // simple, no fields, do nothing
+ Fields::Unit => Ok(()),
+ Fields::Named(ref mut fields) => {
+ skip_serializing_none_add_attr_to_field(fields.named.iter_mut())
+ }
+ Fields::Unnamed(ref mut fields) => {
+ skip_serializing_none_add_attr_to_field(fields.unnamed.iter_mut())
+ }
+ }
+}
diff --git a/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-always.rs b/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-always.rs
new file mode 100644
index 0000000000..b52272439b
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-always.rs
@@ -0,0 +1,30 @@
+extern crate serde;
+extern crate serde_with_macros;
+
+use serde::Serialize;
+use serde_with_macros::skip_serializing_none;
+
+#[skip_serializing_none]
+#[derive(Serialize)]
+struct Data {
+ #[serialize_always]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ a: Option<char>,
+}
+
+#[skip_serializing_none]
+#[derive(Serialize)]
+struct Data2(
+ #[serialize_always]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ Option<char>,
+);
+
+#[skip_serializing_none]
+#[derive(Serialize)]
+struct Data3 {
+ #[serialize_always]
+ a: char,
+}
+
+fn main() {}
diff --git a/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-always.stderr b/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-always.stderr
new file mode 100644
index 0000000000..226d7b55c8
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-always.stderr
@@ -0,0 +1,17 @@
+error: The attributes `serialize_always` and `serde(skip_serializing_if = "...")` cannot be used on the same field: `a`.
+ --> $DIR/skip-none-always.rs:7:1
+ |
+7 | #[skip_serializing_none]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: The attributes `serialize_always` and `serde(skip_serializing_if = "...")` cannot be used on the same field.
+ --> $DIR/skip-none-always.rs:15:1
+ |
+15 | #[skip_serializing_none]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `serialize_always` may only be used on fields of type `Option`.
+ --> $DIR/skip-none-always.rs:23:1
+ |
+23 | #[skip_serializing_none]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-not-struct.rs b/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-not-struct.rs
new file mode 100644
index 0000000000..f6776db778
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-not-struct.rs
@@ -0,0 +1,8 @@
+extern crate serde_with_macros;
+
+use serde_with_macros::skip_serializing_none;
+
+#[skip_serializing_none]
+fn test() {}
+
+fn main() {}
diff --git a/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-not-struct.stderr b/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-not-struct.stderr
new file mode 100644
index 0000000000..479fa7ea75
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/compile-fail/skip-none-not-struct.stderr
@@ -0,0 +1,5 @@
+error: The attribute can only be applied to struct or enum definitions.
+ --> $DIR/skip-none-not-struct.rs:5:1
+ |
+5 | #[skip_serializing_none]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/rust/serde_with_macros/tests/compiler-messages.rs b/third_party/rust/serde_with_macros/tests/compiler-messages.rs
new file mode 100644
index 0000000000..01373a3d3b
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/compiler-messages.rs
@@ -0,0 +1,15 @@
+extern crate rustversion;
+extern crate trybuild;
+
+// This test fails for older compiler versions since the error messages are different.
+#[rustversion::attr(before(1.35), ignore)]
+#[test]
+fn compile_test() {
+ // This test does not work under tarpaulin, so skip it if detected
+ if std::env::var("TARPAULIN") == Ok("1".to_string()) {
+ return;
+ }
+
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/compile-fail/*.rs");
+}
diff --git a/third_party/rust/serde_with_macros/tests/skip_serializing_null.rs b/third_party/rust/serde_with_macros/tests/skip_serializing_null.rs
new file mode 100644
index 0000000000..7fb43bc923
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/skip_serializing_null.rs
@@ -0,0 +1,154 @@
+extern crate pretty_assertions;
+extern crate serde;
+extern crate serde_json;
+extern crate serde_with_macros;
+
+use pretty_assertions::assert_eq;
+use serde::{Deserialize, Serialize};
+use serde_json::json;
+use serde_with_macros::skip_serializing_none;
+
+macro_rules! test {
+ ($fn:ident, $struct:ident) => {
+ #[test]
+ fn $fn() {
+ let expected = json!({});
+ let data = $struct {
+ a: None,
+ b: None,
+ c: None,
+ d: None,
+ };
+ let res = serde_json::to_value(&data).unwrap();
+ assert_eq!(expected, res);
+ assert_eq!(data, serde_json::from_value(res).unwrap());
+ }
+ };
+}
+
+macro_rules! test_tuple {
+ ($fn:ident, $struct:ident) => {
+ #[test]
+ fn $fn() {
+ let expected = json!([]);
+ let data = $struct(None, None);
+ let res = serde_json::to_value(&data).unwrap();
+ assert_eq!(expected, res);
+ }
+ };
+}
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+struct DataBasic {
+ a: Option<String>,
+ b: Option<String>,
+ c: Option<String>,
+ d: Option<String>,
+}
+test!(test_basic, DataBasic);
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+struct DataFullyQualified {
+ a: ::std::option::Option<String>,
+ b: std::option::Option<String>,
+ c: ::std::option::Option<i64>,
+ d: core::option::Option<String>,
+}
+test!(test_fully_qualified, DataFullyQualified);
+
+fn never<T>(_t: &T) -> bool {
+ false
+}
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+struct DataExistingAnnotation {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ a: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none", rename = "abc")]
+ b: Option<String>,
+ #[serde(default)]
+ c: Option<String>,
+ #[serde(skip_serializing_if = "never")]
+ #[serde(rename = "name")]
+ d: Option<String>,
+}
+
+#[test]
+fn test_existing_annotation() {
+ let expected = json!({ "name": null });
+ let data = DataExistingAnnotation {
+ a: None,
+ b: None,
+ c: None,
+ d: None,
+ };
+ let res = serde_json::to_value(&data).unwrap();
+ assert_eq!(expected, res);
+ assert_eq!(data, serde_json::from_value(res).unwrap());
+}
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+struct DataSerializeAlways {
+ #[serialize_always]
+ a: Option<String>,
+ #[serialize_always]
+ b: Option<String>,
+ c: i64,
+ #[serialize_always]
+ d: Option<String>,
+}
+
+#[test]
+fn test_serialize_always() {
+ let expected = json!({
+ "a": null,
+ "b": null,
+ "c": 0,
+ "d": null
+ });
+ let data = DataSerializeAlways {
+ a: None,
+ b: None,
+ c: 0,
+ d: None,
+ };
+ let res = serde_json::to_value(&data).unwrap();
+ assert_eq!(expected, res);
+ assert_eq!(data, serde_json::from_value(res).unwrap());
+}
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize)]
+struct DataTuple(Option<String>, std::option::Option<String>);
+test_tuple!(test_tuple, DataTuple);
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize)]
+enum DataEnum {
+ Tuple(Option<i64>, std::option::Option<bool>),
+ Struct {
+ a: Option<String>,
+ b: Option<String>,
+ },
+}
+
+#[test]
+fn test_enum() {
+ let expected = json!({
+ "Tuple": []
+ });
+ let data = DataEnum::Tuple(None, None);
+ let res = serde_json::to_value(&data).unwrap();
+ assert_eq!(expected, res);
+
+ let expected = json!({
+ "Struct": {}
+ });
+ let data = DataEnum::Struct { a: None, b: None };
+ let res = serde_json::to_value(&data).unwrap();
+ assert_eq!(expected, res);
+}
diff --git a/third_party/rust/serde_with_macros/tests/version_numbers.rs b/third_party/rust/serde_with_macros/tests/version_numbers.rs
new file mode 100644
index 0000000000..9cbd3b3a5a
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/version_numbers.rs
@@ -0,0 +1,6 @@
+extern crate version_sync;
+
+#[test]
+fn test_html_root_url() {
+ version_sync::assert_html_root_url_updated!("src/lib.rs");
+}