Compare commits

...

226 Commits

Author SHA1 Message Date
David Tolnay 017e6d304f Release 0.9.8 2017-02-21 10:59:42 -08:00
David Tolnay 89cbb81673 Include readme and licenses in crates.io archive
Fixes #772.
2017-02-20 21:11:57 -08:00
David Tolnay c36743fa05 Merge pull request #782 from serde-rs/adjacent
Deserialization of Haskell style enums
2017-02-20 21:04:17 -08:00
David Tolnay 9a3c1243f4 Deserialization of Haskell style enums 2017-02-20 20:05:06 -08:00
David Tolnay 599a1b6607 Fragments that keep track of type of syntax
Fixes #777.
2017-02-20 17:12:35 -08:00
David Tolnay 3d6e086d3e Support custom paths in container attribute serde(default="...") 2017-02-20 17:06:00 -08:00
David Tolnay ad480d2b04 Merge pull request #780 from Thomasdezeeuw/default_container
Add support for `#[serde(default)]` on structs
2017-02-20 16:10:28 -08:00
Thomas de Zeeuw 7bee779514 Only allow #[serde(default)]` on structs 2017-02-21 00:15:00 +01:00
David Tolnay dff919a926 Rename __simple_value to __field0 to be consistent with tuples 2017-02-20 14:16:54 -08:00
David Tolnay bac593573c Drop aster dependency 2017-02-20 13:50:17 -08:00
Thomas de Zeeuw 9444db5f19 Add support for #[serde(default)] on structs
This allows structs to use the default value for each field defined in
the struct’s `std::default::Default` implementation, rather then the
default value for the field’s type.

```
struct StructDefault {
    a: i32,
    b: String,
}

impl Default for StructDefault {
    fn default() -> StructDefault {
        StructDefault{
            a: 100,
            b: "default".to_string(),
        }
    }
}
```

The code above will now return `100` for field `a` and `”default”` for
`b`, rather then `0` and `””` respectively.
2017-02-20 22:35:31 +01:00
David Tolnay 3bf8cda994 Update generics handling to use split_for_impl 2017-02-20 13:04:40 -08:00
David Tolnay f98e7f6ba0 Merge pull request #778 from SimonSapin/serialize_display_bounded_length
Avoid some string allocations.
2017-02-20 11:09:32 -08:00
Simon Sapin 772b22b427 Avoid some string allocations. 2017-02-20 18:36:38 +01:00
David Tolnay 535ab1e04b Merge pull request #771 from elliottslaughter:internally_content_tagged 2017-02-19 16:08:49 -08:00
David Tolnay a3fe03c323 Serialization of Haskell style enums 2017-02-19 16:04:39 -08:00
David Tolnay 7dad6426da Merge pull request #774 from nox/limit-hints
Clamp hints coming from untrusted input to 4096
2017-02-19 13:51:21 -08:00
David Tolnay 792a5f7502 Also clamp the collection impls 2017-02-19 13:47:05 -08:00
Anthony Ramine a4c738a9f3 Clamp hints coming from untrusted input to 4096 2017-02-19 14:29:41 +01:00
Elliott Slaughter 4538143d00 Initial work to support serialization of adjacently tagged enums. 2017-02-18 20:46:37 -08:00
David Tolnay 7f08894a32 Remove dependency on unneeded syn feature 2017-02-17 21:01:42 -08:00
David Tolnay adf7b086b5 Remove outdated comment 2017-02-17 20:38:50 -08:00
David Tolnay c590df13b9 Add compile-fail test for the with attribute 2017-02-16 18:43:04 -08:00
Oliver Schneider afa6dfbbe2 Merge pull request #765 from serde-rs/with
Pair serialize_with and deserialize_with into one attribute
2017-02-15 08:33:14 +01:00
David Tolnay f500db6e91 Pair serialize_with and deserialize_with into one attribute 2017-02-14 17:36:50 -08:00
David Tolnay 090c8a7049 Merge pull request #762 from serde-rs/rustfmt
Use rustfmt
2017-02-13 01:29:25 -08:00
David Tolnay e8651a52e7 Rustfmt 2017-02-12 22:15:59 -08:00
David Tolnay 964a2dd4d1 Release 0.9.7 2017-02-09 17:52:11 -08:00
David Tolnay 8a21bbc720 Merge pull request #755 from serde-rs/playground
Playground feature to get serde_derive picked up by integer32 playground
2017-02-09 17:50:39 -08:00
Oliver Schneider 4dba260ad7 Merge pull request #756 from shepmaster/patch-2
Add missing close backtick
2017-02-09 18:01:35 +01:00
Jake Goulding 1d3044fa28 Add missing close backtick 2017-02-09 11:53:12 -05:00
David Tolnay d1f0112bfb Playground feature to get serde_derive picked up by integer32 playground 2017-02-08 12:37:40 -08:00
David Tolnay 3f25cd9a7e No longer need ser::Error import 2017-02-08 08:17:43 -08:00
David Tolnay 45a36f1219 Fix proc macro panic message in tests 2017-02-08 08:12:32 -08:00
David Tolnay 529a1cfedb Keyword no_std for serde and serde_derive 2017-02-08 07:40:02 -08:00
David Tolnay 219abd2e00 The performance is identical 2017-02-04 19:04:29 -08:00
David Tolnay 4bd10528a0 Merge pull request #736 from nox/serialize-iter
Introduce collect_seq and collect_map
2017-02-04 11:18:36 -08:00
David Tolnay b82bba2d0a Merge pull request #747 from serde-rs/phantom_tags
Content clean-up
2017-02-04 08:53:04 -08:00
Anthony Ramine 17c175a1a6 Use specialisation to optimise collect_seq and collect_map 2017-02-04 12:22:58 +01:00
Anthony Ramine 763ab9c2a1 Use serialize_seq! to implement Serialize for [T] 2017-02-04 12:21:45 +01:00
Anthony Ramine 30b8036efa Remove ser::Iterator 2017-02-04 12:17:25 +01:00
Anthony Ramine 89bb16da6b Introduce Serializer::collect_map 2017-02-04 11:49:53 +01:00
Anthony Ramine d00a895902 Introduce Serializer::collect_seq
This function serializes the given iterator as a sequence. Its iter parameter
has type I: IntoIterator, <I as IntoIterator>::Item: Serialize, which means it
will work both for iterators passed by value, therefore consuming them, and as
the value for a #[serde(serialize_with)] attribute, where it will be called as
Serializer::collect_seq(&self.field, serializer), relying on the common practice
of implementing IntoIterator for &C where C is a data type representing some
kind of collection.
2017-02-04 11:49:34 +01:00
Oliver Schneider 393b19ee8a update codegen to the content changes 2017-02-04 10:37:50 +01:00
Oliver Schneider e68888d475 remove possible sublte ambiguity with .into_deserializer 2017-02-04 10:00:04 +01:00
David Tolnay d1306a78ec Release 0.9.6 2017-02-03 08:02:47 -08:00
David Tolnay ce230adf12 Merge pull request #739 from serde-rs/tag
Untagged and internally tagged enums
2017-02-03 07:50:26 -08:00
David Tolnay 066c9a15cf Explain status of content module 2017-02-03 07:43:04 -08:00
Oliver Schneider 6277079152 move the PhantomData usage to the Deserializer 2017-02-03 15:02:40 +01:00
Oliver Schneider d60fd84b7e Merge pull request #740 from serde-rs/enumset
Remove the EnumSet impls
2017-02-03 13:38:39 +01:00
David Tolnay 02e6c04e9f Check for sequence end 2017-02-02 22:13:32 -08:00
David Tolnay 9f04b9d6e7 Remove the EnumSet impls 2017-02-02 19:13:55 -08:00
David Tolnay d298da0b4f Require std for deserializing untagged enums 2017-02-02 19:09:38 -08:00
David Tolnay ff21d557c7 Untagged and internally tagged enums 2017-02-02 18:48:30 -08:00
Oliver Schneider faaa494579 Merge pull request #738 from serde-rs/absolute
Use absolute paths to Ok, Err, and other types and methods
2017-02-02 08:16:51 +01:00
David Tolnay 661cdf4e00 Inline the trait docs at the top level 2017-02-01 12:58:24 -08:00
David Tolnay a55d812441 Even more absolute paths 2017-02-01 12:12:39 -08:00
David Tolnay b7ca574bb3 Use absolute paths to Ok and Err 2017-02-01 09:42:12 -08:00
David Tolnay d960571439 Release 0.9.5 2017-02-01 01:01:06 -08:00
David Tolnay 1ccc58e2aa Merge pull request #735 from serde-rs/travis
Allow running travis build locally
2017-02-01 00:43:27 -08:00
David Tolnay 34b39083bc No error if clippy install fails 2017-02-01 00:38:02 -08:00
David Tolnay 48f4deac55 No more travis-cargo 2017-01-31 12:18:57 -08:00
David Tolnay 9a0f05d00d Speed up the travis clippy installation 2017-01-31 12:09:44 -08:00
David Tolnay b47e1a6dc3 Allow clippy failure in travis 2017-01-31 12:07:35 -08:00
David Tolnay 39c7797633 Allow running travis build locally 2017-01-31 12:07:31 -08:00
Oliver Schneider 368784949e move to cargo clippy instead of using the clippy plugin (#733)
* move to cargo clippy instead of using the clippy plugin

fixes #729

* non-exectable scripts must be run with `sh`

* don't build serde in the clippy travis job

* only run clippy tests if installing clippy succeeds

* why is travis so picky?

* no more serde_codegen

* serde_test_suite_deps has no features

* don't use empty loops, llvm optimizes them to undefined behaviour

* abort the clippy job when clippy lints are triggered

* use caches on travis to speed up builds

* why are we even using `travis-cargo`?

* need to reinstall clippy frequently due to nightly updates

* command line tools are hard
2017-01-31 09:09:37 -08:00
Oliver Schneider 74cf80989d Merge pull request #731 from serde-rs/pubtuple
No tuple structs with private fields in public API
2017-01-31 08:56:46 +01:00
David Tolnay f0b4735781 No tuple structs with private fields in public API 2017-01-30 18:10:50 -08:00
David Tolnay 297f373548 Release 0.9.4 2017-01-30 17:42:11 -08:00
David Tolnay 81f28da8e1 Clarify the role of Impossible serializer 2017-01-30 17:41:33 -08:00
David Tolnay d4bb687032 Merge pull request #728 from nox/impossibru
Introduce ser::Impossible (fixes #694)
2017-01-30 17:26:21 -08:00
Anthony Ramine f9bc5037f5 Introduce ser::Impossible (fixes #694) 2017-01-31 02:20:04 +01:00
David Tolnay 8624ca6f1d Release 0.9.3 2017-01-28 15:01:58 -08:00
David Tolnay a9b5cc4830 Fix invalid_length message for tuples and arrays 2017-01-28 15:00:54 -08:00
David Tolnay c31f76321c Release 0.9.2 2017-01-28 09:10:39 -08:00
David Tolnay f2402dcf52 Merge pull request #724 from serde-rs/entry
SerializeMap::serialize_entry
2017-01-28 09:08:51 -08:00
David Tolnay 361402ac4d SerializeMap::serialize_entry 2017-01-28 09:03:32 -08:00
David Tolnay c52e131a03 Replace deprecated MacroInput 2017-01-27 15:42:43 -08:00
David Tolnay c0a06bdc96 Update to syn 0.11 2017-01-27 15:25:42 -08:00
David Tolnay dd13fd3a34 Isolate the compiletest dependencies 2017-01-27 14:53:30 -08:00
David Tolnay 91f628727b Clean up the compile_tests script 2017-01-27 14:37:28 -08:00
David Tolnay 571a2e4e2d Indent the travis config to look like serde_json's 2017-01-27 14:17:07 -08:00
David Tolnay 7edcf6ec3b Simplify Error::custom example 2017-01-27 14:03:40 -08:00
David Tolnay e4f7d8513c Clean up clippy lints in codegen_internals 2017-01-25 21:22:15 -08:00
David Tolnay 09c69da909 Move test macro to where it is used 2017-01-25 20:55:55 -08:00
David Tolnay 7ee175f448 Remove duplicate btreemap macro 2017-01-25 20:54:31 -08:00
David Tolnay 70ab3cdd61 Docs are built in a different repo 2017-01-25 20:51:10 -08:00
David Tolnay 8fb554e593 Rename no_std tests to underscores 2017-01-25 20:50:23 -08:00
David Tolnay 7a2bfdc1dd Consistent underscores in root directory 2017-01-25 20:45:33 -08:00
David Tolnay 9046e9d7a1 Test suite requires beta for now 2017-01-25 20:45:08 -08:00
David Tolnay 87040b4bc4 Fix clippy lints in serde_test 2017-01-25 20:42:44 -08:00
David Tolnay 68aab2424f Rename test suite crate 2017-01-25 20:40:13 -08:00
David Tolnay 9b9b697eb1 Make compiletest an optional dependency of the test suite 2017-01-25 20:39:27 -08:00
David Tolnay db449c4bf2 Set up clippy for serde_test 2017-01-25 20:38:21 -08:00
David Tolnay 948aa47687 Clean up clippy lints 2017-01-25 20:34:01 -08:00
David Tolnay 3e1e42ef9b Combine the test suites 2017-01-25 20:29:09 -08:00
David Tolnay dbdfe4f306 Remove serde_codegen from the test suite 2017-01-25 20:19:16 -08:00
David Tolnay e0d6b9d010 Merge serde_codegen into serde_derive crate 2017-01-25 20:07:55 -08:00
David Tolnay a5b8e806f8 Remove with-syntex feature of serde_codegen 2017-01-25 20:02:24 -08:00
David Tolnay d7dadd83b6 Remove the syntex example 2017-01-25 19:54:24 -08:00
David Tolnay 7612fd8e82 Release 0.9.1 2017-01-25 14:58:22 -08:00
David Tolnay 4c77af53e5 Clean up dependency declarations 2017-01-25 14:54:32 -08:00
David Tolnay 5d9c1aeb06 Release 0.9.0 2017-01-25 12:57:45 -08:00
David Tolnay 59e48997dd Release 0.9.0-rc4 2017-01-25 10:14:43 -08:00
Oliver Schneider ffcd97834f Merge pull request #721 from serde-rs/size
Remove usize and isize from data model
2017-01-25 19:08:02 +01:00
David Tolnay e0c049dbf2 Remove usize and isize from data model 2017-01-25 09:08:06 -08:00
David Tolnay 8cb6607e82 Merge pull request #719 from serde-rs/rustdoc
Serde rustdoc
2017-01-24 20:59:26 -08:00
David Tolnay 1ffb0570b6 Do not require rustdoc tests to run on stable 2017-01-24 20:47:31 -08:00
David Tolnay 2c1dd60575 Serde rustdoc 2017-01-24 20:37:11 -08:00
David Tolnay 24f849da2d Remove unused #[macro_use]
I think this was for the quasi-quoting macros back in the day.
2017-01-24 09:28:00 -08:00
David Tolnay a5024a4238 Merge pull request #717 from serde-rs/badger
add travis badge to crates.io
2017-01-24 05:35:55 -08:00
Oliver Schneider b105423e5e add travis badge to crates.io 2017-01-24 10:30:10 +01:00
Oliver Schneider 42c1bc2907 Merge pull request #716 from serde-rs/ref
Serialize T by ref
2017-01-24 08:31:24 +01:00
David Tolnay c334c1c7b5 Release 0.9.0-rc3 2017-01-23 19:14:02 -08:00
David Tolnay 92668d7061 Serialize T by ref 2017-01-23 17:11:18 -08:00
David Tolnay b9d865d8e7 Merge pull request #715 from serde-rs/nostd
Support serde_derive on no_std
2017-01-23 16:13:25 -08:00
David Tolnay fc4e370ba9 Support serde_derive on no_std 2017-01-23 16:03:06 -08:00
Oliver Schneider a982d27536 Merge pull request #700 from serde-rs/usize
Restore visit_usize and visit_bytes for identifying variants
2017-01-23 11:27:06 +01:00
Oliver Schneider dc87826298 Merge pull request #699 from serde-rs/fields
Remove visit_usize from Duration impl
2017-01-23 11:26:18 +01:00
David Tolnay a09a8a039a All combinations of features compile without warnings 2017-01-23 01:45:54 -08:00
David Tolnay ea702755a2 Merge branch master into origin/usize
Conflicts:
    serde_codegen/src/de.rs
    testing/tests/test_de.rs
2017-01-23 01:36:49 -08:00
David Tolnay d161911c63 Merge branch master into origin/fields
Conflicts:
    serde/src/de/impls.rs
2017-01-23 01:28:01 -08:00
Oliver Schneider e27553d3df Merge pull request #710 from serde-rs/errors
Errors redesign
2017-01-23 10:25:48 +01:00
David Tolnay 48eaf988bc Add free-form option for Unexpected 2017-01-22 05:02:24 -08:00
David Tolnay 73a364d4fd Capture byte value for error message 2017-01-22 04:57:12 -08:00
David Tolnay 6dfdcb6ba1 Merge pull request #713 from serde-rs/zero
Suppress warning about using num::Zero
2017-01-21 19:20:57 -08:00
David Tolnay 089c7eb1d7 Suppress warning about using num::Zero 2017-01-21 19:14:56 -08:00
David Tolnay 1e05fc2145 Release 0.9.0-rc2 2017-01-21 16:30:13 -08:00
David Tolnay 977612d8dd Merge branch origin/missing into origin/errors 2017-01-21 16:28:24 -08:00
David Tolnay 5855078703 Fix backward invalid_length messages in value deserializer 2017-01-21 14:38:33 -08:00
David Tolnay 3c88a93fb2 Fix the filtered error messages 2017-01-21 12:34:04 -08:00
David Tolnay 530c29466e Merge pull request #711 from serde-rs/names
Filter the slice of expected field and variant names
2017-01-21 12:25:43 -08:00
David Tolnay ea99e8b686 Filter the slice of expected field and variant names 2017-01-21 12:18:55 -08:00
David Tolnay 2a148112d4 Fix Box<str> use on no_std 2017-01-21 10:17:48 -08:00
David Tolnay a4126e4c5a Errors 2017-01-21 09:13:01 -08:00
David Tolnay d1325862f7 Merge tag v0.8.23 into master
Conflicts:
    serde/Cargo.toml
    serde_codegen/Cargo.toml
    serde_derive/Cargo.toml
    serde_test/Cargo.toml
    testing/Cargo.toml
2017-01-20 15:29:32 -08:00
David Tolnay 1f65ce75ec Release 0.8.23 2017-01-20 15:25:57 -08:00
Jake Goulding 9536e52aa6 Add categories to Cargo.toml 2017-01-20 15:09:11 -08:00
Oliver Schneider be0c755731 Merge pull request #705 from serde-rs/inlineseed
Inline <PhantomData<T> as DeserializeSeed>::deserialize
2017-01-20 14:34:24 +01:00
David Tolnay 42bc63bed8 Standardize behavior of missing fields 2017-01-20 00:44:43 -08:00
David Tolnay e41b940a3d Inline <PhantomData<T> as DeserializeSeed>::deserialize 2017-01-19 16:17:27 -08:00
David Tolnay 88149fc0c3 Fix key and value seed variable names
Rename fail.
2017-01-19 13:44:18 -08:00
David Tolnay 5ecfb3b388 Update serde_test to use seeds 2017-01-19 01:24:33 -08:00
David Tolnay 13a9f929de Stateful deserialization 2017-01-19 01:17:59 -08:00
David Tolnay e40fbe0767 Restore visit_bytes for Duration impl 2017-01-18 21:13:51 -08:00
David Tolnay 0a10116bf5 Restore visit_bytes for identifying variants and fields 2017-01-18 21:11:51 -08:00
David Tolnay b1fbbfd3ce Restore visit_usize for identifying variants 2017-01-17 23:52:06 -08:00
David Tolnay 984ebcead0 Remove visit_usize and visit_bytes for Duration impl 2017-01-17 23:32:28 -08:00
David Tolnay aa88f01cdc Merge pull request #697 from serde-rs/vanity
cleanup some deprecation warnings
2017-01-17 09:26:44 -08:00
David Tolnay 13794c1b48 Stop testing on rust 1.12.0 2017-01-17 09:19:39 -08:00
Oliver Schneider b5e64abba1 cleanup some deprecation warnings 2017-01-17 14:29:33 +01:00
David Tolnay 503ce310f5 Merge pull request #692 from serde-rs/byte_buf
add missing `Vec<u8>` deserialization hint to `Deserializer`
2017-01-16 08:10:25 -08:00
Oliver Schneider b26f291d93 add missing Vec<u8> deserialization hint to Deserializer 2017-01-16 16:55:13 +01:00
David Tolnay bc6bc9e3f0 Remove LICENSE file in favor of LICENSE-MIT and LICENSE-APACHE
This repo no longer contains bench_log referenced in this file.
2017-01-15 10:16:57 -08:00
David Tolnay 3a52364f3e Release 0.9.0-rc1 2017-01-15 09:26:44 -08:00
David Tolnay 4d1627fc96 Merge pull request #687 from serde-rs/ser
Enforce correct use of Serialize trait
2017-01-15 09:22:30 -08:00
David Tolnay 7c04bf36d9 Merge pull request #686 from serde-rs/de
Enforce correct use of Deserialize trait
2017-01-15 07:30:14 -08:00
David Tolnay 4b06030666 Unabbreviated method naming 2017-01-14 21:39:37 -08:00
David Tolnay a5a04306f2 Update tests for Serializer changes 2017-01-14 16:07:43 -08:00
David Tolnay f9885c4826 Update serde_codegen for Serializer changes 2017-01-14 16:07:34 -08:00
David Tolnay 04f25eb122 Update serde_test for Serializer changes 2017-01-14 16:07:17 -08:00
David Tolnay 2fea5f3e1c Enforce correct use of Serialize trait 2017-01-14 15:21:31 -08:00
David Tolnay 905b2c3cf3 Expose VariantVisitor for the StrDeserializer 2017-01-14 14:17:46 -08:00
David Tolnay d5b428a087 Fix imports for stable compiler 2017-01-14 14:16:01 -08:00
David Tolnay b3b8056d93 Update tests for Deserializer changes 2017-01-14 13:42:49 -08:00
David Tolnay 137cf9bab8 Update serde_codegen for Deserializer changes 2017-01-14 13:42:48 -08:00
David Tolnay 7372f152bd Update serde_test for Deserializer changes 2017-01-14 13:42:45 -08:00
David Tolnay a43da15b74 Merge pull request #685 from mineo/patch-1
Typo: aggrergate -> aggregate
2017-01-14 13:36:49 -08:00
Wieland Hoffmann 212cbbd8bf Typo: aggrergate -> aggregate 2017-01-14 22:33:31 +01:00
David Tolnay 738aa31733 Enforce correct use of Deserialize trait 2017-01-14 12:16:08 -08:00
Oliver Schneider 787ecc6a82 Merge pull request #684 from serde-rs/end
Remove SeqVisitor::end() and MapVisitor::end()
2017-01-14 08:01:53 +01:00
David Tolnay 9fc8a86bcc Exclude serde-syntex-example until serde_json has been updated 2017-01-13 13:34:41 -08:00
David Tolnay 800442a75e Handle visitor that does not need to be mutable 2017-01-13 13:34:39 -08:00
David Tolnay 88debb3fb8 Remove SeqVisitor::end() and MapVisitor::end() 2017-01-13 13:34:38 -08:00
David Tolnay 88a4ed9cd7 Include missing_field in impl MapVisitor for &mut MapVisitor 2017-01-13 13:33:37 -08:00
David Tolnay bdba6fc5b0 Remove the proc_macro feature gate in serde-syntex-example 2017-01-13 10:27:51 -08:00
Oliver Schneider dec116311e Merge pull request #682 from serde-rs/unknown
Treat skipped fields as unknown
2017-01-13 10:46:18 +01:00
David Tolnay 8c49e6d6a5 Resolve conflict between rename changes and skip changes 2017-01-13 01:27:07 -08:00
David Tolnay 7cc24a43fb Merge branch master into unknown
Conflicts:
    serde_codegen/src/de.rs
2017-01-13 01:23:00 -08:00
David Tolnay c008c6d3a8 Merge pull request #681 from serde-rs/deserialize_struct_bug
fix various serde(rename) bugs
2017-01-13 01:21:46 -08:00
David Tolnay c9f5d08ed1 Add test for all variants skipped 2017-01-13 01:14:03 -08:00
David Tolnay fff6c9cb66 Add tests for all fields skipped 2017-01-13 01:12:31 -08:00
David Tolnay cb5e7c6264 Fix case of skipped variant followed by other variants 2017-01-12 23:35:39 -08:00
David Tolnay 4ef1128546 More explicit about argument to deserialize_field_visitor 2017-01-12 23:30:57 -08:00
David Tolnay 227bea1d0b Treat skipped fields as unknown 2017-01-12 23:17:45 -08:00
David Tolnay 766ede965e Eliminate collects in codegen for deserializing map 2017-01-12 21:52:56 -08:00
David Tolnay eb5a49e380 Use helper function to build __field{} 2017-01-12 21:49:20 -08:00
David Tolnay 2df529cac5 Simplify codegen logic in deserializing seq 2017-01-12 21:41:27 -08:00
David Tolnay 4b66463011 Eliminate collect in deserializing seq 2017-01-12 21:29:50 -08:00
David Tolnay b907cfef85 Eliminate collect in visitor generics 2017-01-12 21:28:09 -08:00
David Tolnay 506c8cc087 Simplify the trait paths used in bounds 2017-01-12 21:24:51 -08:00
David Tolnay 3951ef91c0 Don't need aster to construct syn::Ident 2017-01-12 21:15:13 -08:00
David Tolnay b0d20afdfb Merge pull request #680 from serde-rs/oli-obk-patch-1
make `ser::iterator` more general by taking `IntoIterator`
2017-01-12 16:45:39 -08:00
Oliver Schneider 5e6ee523d2 remove duplicate into_iter 2017-01-12 21:52:38 +01:00
Oliver Schneider a07b6bd9e7 also use the renamed variant names during deserialization 2017-01-12 20:21:59 +01:00
Oliver Schneider 8dd06eed2f type inference failure 2017-01-12 20:19:00 +01:00
Oliver Schneider 5b668ed87a attempt to test the field names, but deem it too complex and opt to at least improve the code 2017-01-12 20:17:55 +01:00
Oliver Schneider abe305dbfe fix deserialize_struct passing the original field names instead of the renamed ones 2017-01-12 20:17:02 +01:00
Oliver Schneider 2d1a60c056 Update the Serialize impl, too 2017-01-12 20:06:44 +01:00
Oliver Schneider 5edfdba940 use IntoIterator everywhere 2017-01-12 20:05:26 +01:00
Oliver Schneider 756bff534f make ser::iterator more general by taking IntoIterator 2017-01-12 19:24:35 +01:00
David Tolnay 110d36fa14 Merge pull request #679 from oli-obk/iterators
add wrapper to serde that allows serializing iterators as sequences
2017-01-12 10:19:09 -08:00
Oliver Schneider 8c576fe9fb rename IteratorSerializer to Iterator 2017-01-12 17:29:04 +01:00
Oliver Schneider b860d3cb1f fix tests on stable 2017-01-12 16:06:26 +01:00
Oliver Schneider dced4416a7 add wrapper to serde that allows serializing iterators as sequences 2017-01-12 15:31:40 +01:00
David Tolnay ca47eb929c Merge pull request #678 from serde-rs/empty
Handle various degenerate cases
2017-01-11 11:45:24 -08:00
David Tolnay b01c23b5ee Also provide a smarter alternative for the other impossible case 2017-01-11 11:34:47 -08:00
David Tolnay 3aaf29c846 Remove ref in top-level let pattern
Discouraged by Clippy.
2017-01-11 11:12:53 -08:00
David Tolnay d2eea87001 Handle various degenerate cases 2017-01-11 11:02:24 -08:00
David Tolnay 8242c64152 Merge branch v0.8 into master 2017-01-10 17:16:31 -08:00
Oliver Schneider 405b534254 Merge pull request #674 from serde-rs/nonascii
Add test for non ascii idents
2017-01-10 11:16:19 +01:00
David Tolnay d34be74dfd Add test for non ascii idents 2017-01-10 01:20:01 -08:00
David Tolnay c475df8320 Encourage GitHub issues 2017-01-09 14:44:36 -08:00
Oliver Schneider 2b8a620807 Merge pull request #671 from serde-rs/fields
Stop generating visit_usize and visit_bytes for FieldVisitor
2017-01-09 13:09:18 +01:00
David Tolnay 1cd6aee562 Merge pull request #670 from serde-rs/error
Stop exporting serde::de::Error as serde::Error
2017-01-09 00:45:04 -08:00
David Tolnay 90d4d7b37b Restore the old FieldVisitor tests as error tests 2017-01-09 00:43:13 -08:00
David Tolnay 1f8b803607 Repetition for field visitor arms 2017-01-09 00:37:37 -08:00
David Tolnay 516cc8b04e Stop generating visit_usize and visit_bytes for FieldVisitor 2017-01-08 01:01:56 -08:00
David Tolnay 0676477cd7 Stop exporting serde::de::Error as serde::Error 2017-01-08 00:50:07 -08:00
David Tolnay 4193122472 Use the more concise paths in generated code 2017-01-08 00:47:44 -08:00
David Tolnay eb6fb1d40e Merge pull request #523 from serde-rs/enum
Enum deserialization API
2017-01-08 00:45:50 -08:00
David Tolnay bf873a7b3f Merge branch origin/master into origin/enum
Conflicts:
    serde/src/de/mod.rs
    serde_codegen/src/de.rs
    testing/tests/test_bytes.rs
2017-01-08 00:31:07 -08:00
David Tolnay fbd4a17467 Merge pull request #664 from serde-rs/visitor-value
Remove the Deserialize trait bound on Visitor::Value
2017-01-08 00:24:53 -08:00
David Tolnay ad34c14c8c Prepare for 0.9 breaking changes 2017-01-08 00:18:53 -08:00
David Tolnay 7a0e8f73b4 Remove the Deserialize trait bound on Visitor::Value 2017-01-03 01:50:10 -08:00
David Tolnay 85f1bf0259 Enum deserialization API 2016-08-23 22:17:28 -04:00
102 changed files with 9137 additions and 5689 deletions
+14 -24
View File
@@ -1,27 +1,17 @@
sudo: false
language: rust
cache: cargo
# run builds for all the trains (and more)
rust:
- 1.12.0
- 1.13.0
- stable
- beta
- nightly
before_script:
- pip install 'travis-cargo<0.2' --user
- export PATH=$HOME/.local/bin:$PATH
script:
- (cd serde && travis-cargo build)
- (cd serde && travis-cargo --skip nightly test)
- (cd serde && travis-cargo --only nightly test -- --features unstable-testing)
- (cd serde && travis-cargo build -- --no-default-features)
- (cd serde && travis-cargo --only nightly build -- --no-default-features --features alloc)
- (cd serde && travis-cargo --only nightly build -- --no-default-features --features collections)
- (cd testing && travis-cargo --skip nightly test)
- (cd testing && travis-cargo --only nightly test -- --features unstable-testing)
- (cd serde_derive && travis-cargo --only nightly test)
- (cd examples/serde-syntex-example && travis-cargo --skip nightly run)
- (cd examples/serde-syntex-example && travis-cargo --only nightly run -- --no-default-features --features unstable)
- (cd serde && travis-cargo --only stable doc)
env:
global:
- TRAVIS_CARGO_NIGHTLY_FEATURE=""
- 1.13.0
- stable
- beta
- nightly
matrix:
include:
- rust: nightly
env: CLIPPY=true
script: ./travis.sh
+9
View File
@@ -0,0 +1,9 @@
[workspace]
members = [
"serde",
"serde_codegen_internals",
"serde_derive",
"serde_test",
"test_suite",
"test_suite/no_std",
]
-33
View File
@@ -1,33 +0,0 @@
See LICENSE-APACHE and LICENSE-MIT.
----
bench_log is derived from https://github.com/cloudflare/goser, which has the
following license:
Copyright (c) 2013, CloudFlare, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+3 -2
View File
@@ -49,8 +49,9 @@ fn main() {
Serde developers live in the #serde channel on
[`irc.mozilla.org`](https://wiki.mozilla.org/IRC). The #rust channel is also a
good resource with generally faster response time but less specific knowledge
about Serde. If IRC is not your thing, we are happy to respond to [GitHub
issues](https://github.com/serde-rs/serde/issues/new) as well.
about Serde. If IRC is not your thing or you don't get a good response, we are
happy to respond to [GitHub issues](https://github.com/serde-rs/serde/issues/new)
as well.
## License
-2
View File
@@ -1,2 +0,0 @@
target
Cargo.lock
-18
View File
@@ -1,18 +0,0 @@
[package]
name = "serde-syntex-example"
version = "0.1.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
build = "build.rs"
publish = false
[features]
default = ["serde_codegen"]
unstable = ["serde_derive"]
[build-dependencies]
serde_codegen = { version = "^0.8", optional = true, path = "../../serde_codegen" }
[dependencies]
serde = "^0.8"
serde_derive = { version = "^0.8", optional = true, path = "../../serde_derive" }
serde_json = "^0.8"
-20
View File
@@ -1,20 +0,0 @@
This example demonstrates how to use Serde with Syntex. On stable or nightly
with Syntex, it can be built with:
```
% rustup run stable cargo run
Running `target/debug/serde-syntex-example`
{"x":1,"y":2}
Point { x: 1, y: 2 }
% rustup run nightly cargo run
Running `target/debug/serde-syntex-example`
{"x":1,"y":2}
Point { x: 1, y: 2 }
```
On nightly, it can use a plugin with:
```
% rustup run nightly cargo run --features unstable --no-default-features
```
-25
View File
@@ -1,25 +0,0 @@
#[cfg(not(feature = "serde_derive"))]
mod inner {
extern crate serde_codegen;
use std::env;
use std::path::Path;
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let src = Path::new("src/main.rs.in");
let dst = Path::new(&out_dir).join("main.rs");
serde_codegen::expand(&src, &dst).unwrap();
}
}
#[cfg(feature = "serde_derive")]
mod inner {
pub fn main() {}
}
fn main() {
inner::main();
}
-14
View File
@@ -1,14 +0,0 @@
#![cfg_attr(feature = "serde_derive", feature(proc_macro))]
#[cfg(feature = "serde_derive")]
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
#[cfg(feature = "serde_derive")]
include!("main.rs.in");
#[cfg(not(feature = "serde_derive"))]
include!(concat!(env!("OUT_DIR"), "/main.rs"));
@@ -1,16 +0,0 @@
#[derive(Serialize, Deserialize, Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point = Point { x: 1, y: 2 };
let serialized = serde_json::to_string(&point).unwrap();
println!("{}", serialized);
let deserialized: Point = serde_json::from_str(&serialized).unwrap();
println!("{:?}", deserialized);
}
+15 -5
View File
@@ -1,15 +1,19 @@
[package]
name = "serde"
version = "0.8.22"
version = "0.9.8"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://docs.serde.rs/serde/"
keywords = ["serde", "serialization", "no_std"]
categories = ["encoding"]
readme = "../README.md"
keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
[badges]
travis-ci = { repository = "serde-rs/serde" }
[features]
default = ["std"]
@@ -18,7 +22,13 @@ std = []
unstable = []
alloc = ["unstable"]
collections = ["alloc"]
unstable-testing = ["clippy", "unstable", "std"]
unstable-testing = ["unstable", "std"]
# to get serde_derive picked up by play.integer32.com
playground = ["serde_derive"]
[dependencies]
clippy = { version = "^0.*", optional = true }
serde_derive = { version = "0.9", optional = true }
[dev-dependencies]
serde_derive = "0.9"
+1
View File
@@ -0,0 +1 @@
../LICENSE-APACHE
+1
View File
@@ -0,0 +1 @@
../LICENSE-MIT
+1
View File
@@ -0,0 +1 @@
../README.md
+96 -33
View File
@@ -1,4 +1,20 @@
//! Helper module to enable serializing bytes more efficiently
//! Wrapper types to enable optimized handling of `&[u8]` and `Vec<u8>`.
//!
//! Without specialization, Rust forces us to treat `&[u8]` just like any other
//! slice and `Vec<u8>` just like any other vector. In reality this particular
//! slice and vector can often be serialized and deserialized in a more
//! efficient, compact representation in many formats.
//!
//! When working with such a format, you can opt into specialized handling of
//! `&[u8]` by wrapping it in `bytes::Bytes` and `Vec<u8>` by wrapping it in
//! `bytes::ByteBuf`.
//!
//! Rust support for specialization is being tracked in
//! [rust-lang/rust#31844][specialization]. Once it lands in the stable compiler
//! we will be deprecating these wrapper types in favor of optimizing `&[u8]`
//! and `Vec<u8>` out of the box.
//!
//! [specialization]: https://github.com/rust-lang/rust/issues/31844
use core::{ops, fmt, char, iter, slice};
use core::fmt::Write;
@@ -6,14 +22,36 @@ use core::fmt::Write;
use ser;
#[cfg(any(feature = "std", feature = "collections"))]
pub use self::bytebuf::{ByteBuf, ByteBufVisitor};
pub use self::bytebuf::ByteBuf;
#[cfg(any(feature = "std", feature = "collections"))]
#[doc(hidden)] // does anybody need this?
pub use self::bytebuf::ByteBufVisitor;
#[cfg(feature = "collections")]
use collections::Vec;
///////////////////////////////////////////////////////////////////////////////
/// `Bytes` wraps a `&[u8]` in order to serialize into a byte array.
/// Wraps a `&[u8]` in order to serialize in an efficient way. Does not support
/// deserialization.
///
/// ```rust
/// # #[macro_use] extern crate serde_derive;
/// # extern crate serde;
/// # use std::net::IpAddr;
/// #
/// use serde::bytes::Bytes;
///
/// # #[allow(dead_code)]
/// #[derive(Serialize)]
/// struct Packet<'a> {
/// destination: IpAddr,
/// payload: Bytes<'a>,
/// }
/// #
/// # fn main() {}
/// ```
#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct Bytes<'a> {
bytes: &'a [u8],
@@ -22,9 +60,7 @@ pub struct Bytes<'a> {
impl<'a> Bytes<'a> {
/// Wrap an existing `&[u8]`.
pub fn new(bytes: &'a [u8]) -> Self {
Bytes {
bytes: bytes,
}
Bytes { bytes: bytes }
}
}
@@ -60,12 +96,14 @@ impl<'a> Into<&'a [u8]> for Bytes<'a> {
impl<'a> ops::Deref for Bytes<'a> {
type Target = [u8];
fn deref(&self) -> &[u8] { self.bytes }
fn deref(&self) -> &[u8] {
self.bytes
}
}
impl<'a> ser::Serialize for Bytes<'a> {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: ser::Serializer
{
serializer.serialize_bytes(self.bytes)
@@ -76,6 +114,7 @@ impl<'a> ser::Serialize for Bytes<'a> {
#[cfg(any(feature = "std", feature = "collections"))]
mod bytebuf {
use core::cmp;
use core::ops;
use core::fmt;
use core::fmt::Write;
@@ -86,7 +125,25 @@ mod bytebuf {
#[cfg(feature = "collections")]
use collections::{String, Vec};
/// `ByteBuf` wraps a `Vec<u8>` and serializes as a byte array.
/// Wraps a `Vec<u8>` in order to serialize and deserialize in an efficient
/// way.
///
/// ```rust
/// # #[macro_use] extern crate serde_derive;
/// # extern crate serde;
/// # use std::net::IpAddr;
/// #
/// use serde::bytes::ByteBuf;
///
/// # #[allow(dead_code)]
/// #[derive(Serialize, Deserialize)]
/// struct Packet {
/// destination: IpAddr,
/// payload: ByteBuf,
/// }
/// #
/// # fn main() {}
/// ```
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ByteBuf {
bytes: Vec<u8>,
@@ -105,9 +162,7 @@ mod bytebuf {
/// Wrap existing bytes in a `ByteBuf`.
pub fn from<T: Into<Vec<u8>>>(bytes: T) -> Self {
ByteBuf {
bytes: bytes.into(),
}
ByteBuf { bytes: bytes.into() }
}
}
@@ -160,15 +215,19 @@ mod bytebuf {
impl ops::Deref for ByteBuf {
type Target = [u8];
fn deref(&self) -> &[u8] { &self.bytes[..] }
fn deref(&self) -> &[u8] {
&self.bytes[..]
}
}
impl ops::DerefMut for ByteBuf {
fn deref_mut(&mut self) -> &mut [u8] { &mut self.bytes[..] }
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.bytes[..]
}
}
impl ser::Serialize for ByteBuf {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: ser::Serializer
{
serializer.serialize_bytes(self)
@@ -181,51 +240,53 @@ mod bytebuf {
impl de::Visitor for ByteBufVisitor {
type Value = ByteBuf;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("byte array")
}
#[inline]
fn visit_unit<E>(&mut self) -> Result<ByteBuf, E>
where E: de::Error,
fn visit_unit<E>(self) -> Result<ByteBuf, E>
where E: de::Error
{
Ok(ByteBuf::new())
}
#[inline]
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<ByteBuf, V::Error>
where V: de::SeqVisitor,
fn visit_seq<V>(self, mut visitor: V) -> Result<ByteBuf, V::Error>
where V: de::SeqVisitor
{
let (len, _) = visitor.size_hint();
let len = cmp::min(visitor.size_hint().0, 4096);
let mut values = Vec::with_capacity(len);
while let Some(value) = try!(visitor.visit()) {
values.push(value);
}
try!(visitor.end());
Ok(ByteBuf::from(values))
}
#[inline]
fn visit_bytes<E>(&mut self, v: &[u8]) -> Result<ByteBuf, E>
where E: de::Error,
fn visit_bytes<E>(self, v: &[u8]) -> Result<ByteBuf, E>
where E: de::Error
{
Ok(ByteBuf::from(v))
}
#[inline]
fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<ByteBuf, E>
where E: de::Error,
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<ByteBuf, E>
where E: de::Error
{
Ok(ByteBuf::from(v))
}
fn visit_str<E>(&mut self, v: &str) -> Result<ByteBuf, E>
where E: de::Error,
fn visit_str<E>(self, v: &str) -> Result<ByteBuf, E>
where E: de::Error
{
Ok(ByteBuf::from(v))
}
fn visit_string<E>(&mut self, v: String) -> Result<ByteBuf, E>
where E: de::Error,
fn visit_string<E>(self, v: String) -> Result<ByteBuf, E>
where E: de::Error
{
Ok(ByteBuf::from(v))
}
@@ -233,10 +294,10 @@ mod bytebuf {
impl de::Deserialize for ByteBuf {
#[inline]
fn deserialize<D>(deserializer: &mut D) -> Result<ByteBuf, D::Error>
fn deserialize<D>(deserializer: D) -> Result<ByteBuf, D::Error>
where D: de::Deserializer
{
deserializer.deserialize_bytes(ByteBufVisitor)
deserializer.deserialize_byte_buf(ByteBufVisitor)
}
}
}
@@ -244,7 +305,9 @@ mod bytebuf {
///////////////////////////////////////////////////////////////////////////////
#[inline]
fn escape_bytestring<'a>(bytes: &'a [u8]) -> iter::FlatMap<slice::Iter<'a, u8>, char::EscapeDefault, fn(&u8) -> char::EscapeDefault> {
fn escape_bytestring<'a>
(bytes: &'a [u8])
-> iter::FlatMap<slice::Iter<'a, u8>, char::EscapeDefault, fn(&u8) -> char::EscapeDefault> {
fn f(b: &u8) -> char::EscapeDefault {
char::from_u32(*b as u32).unwrap().escape_default()
}
+797
View File
@@ -0,0 +1,797 @@
// This module is doc(hidden) and nothing here should be used outside of
// generated code.
//
// We will iterate on the implementation for a few releases and only have to
// worry about backward compatibility for the `untagged` and `tag` attributes
// rather than for this entire mechanism.
//
// This issue is tracking making some of this stuff public:
// https://github.com/serde-rs/serde/issues/741
#![doc(hidden)]
use core::cmp;
use core::fmt;
use core::marker::PhantomData;
#[cfg(all(not(feature = "std"), feature = "collections"))]
use collections::{String, Vec};
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::boxed::Box;
use de::{self, Deserialize, DeserializeSeed, Deserializer, Visitor, SeqVisitor, MapVisitor,
EnumVisitor, Unexpected};
/// Used from generated code to buffer the contents of the Deserializer when
/// deserializing untagged enums and internally tagged enums.
///
/// Not public API. Use serde-value instead.
#[derive(Debug)]
pub enum Content {
// Don't mind the PhantomData, just need to use E somewhere.
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
F32(f32),
F64(f64),
Char(char),
String(String),
Bytes(Vec<u8>),
None,
Some(Box<Content>),
Unit,
Newtype(Box<Content>),
Seq(Vec<Content>),
Map(Vec<(Content, Content)>),
}
impl Deserialize for Content {
fn deserialize<D: Deserializer>(deserializer: D) -> Result<Self, D::Error> {
// Untagged and internally tagged enums are only supported in
// self-describing formats.
deserializer.deserialize(ContentVisitor)
}
}
struct ContentVisitor;
impl Visitor for ContentVisitor {
type Value = Content;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("any value")
}
fn visit_bool<F>(self, value: bool) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::Bool(value))
}
fn visit_i8<F>(self, value: i8) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::I8(value))
}
fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::I16(value))
}
fn visit_i32<F>(self, value: i32) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::I32(value))
}
fn visit_i64<F>(self, value: i64) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::I64(value))
}
fn visit_u8<F>(self, value: u8) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::U8(value))
}
fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::U16(value))
}
fn visit_u32<F>(self, value: u32) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::U32(value))
}
fn visit_u64<F>(self, value: u64) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::U64(value))
}
fn visit_f32<F>(self, value: f32) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::F32(value))
}
fn visit_f64<F>(self, value: f64) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::F64(value))
}
fn visit_char<F>(self, value: char) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::Char(value))
}
fn visit_str<F>(self, value: &str) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::String(value.into()))
}
fn visit_string<F>(self, value: String) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::String(value))
}
fn visit_bytes<F>(self, value: &[u8]) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::Bytes(value.into()))
}
fn visit_byte_buf<F>(self, value: Vec<u8>) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::Bytes(value))
}
fn visit_unit<F>(self) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::Unit)
}
fn visit_none<F>(self) -> Result<Self::Value, F>
where F: de::Error
{
Ok(Content::None)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where D: Deserializer
{
Deserialize::deserialize(deserializer).map(|v| Content::Some(Box::new(v)))
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where D: Deserializer
{
Deserialize::deserialize(deserializer).map(|v| Content::Newtype(Box::new(v)))
}
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where V: SeqVisitor
{
let mut vec = Vec::with_capacity(cmp::min(visitor.size_hint().0, 4096));
while let Some(e) = try!(visitor.visit()) {
vec.push(e);
}
Ok(Content::Seq(vec))
}
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where V: MapVisitor
{
let mut vec = Vec::with_capacity(cmp::min(visitor.size_hint().0, 4096));
while let Some(kv) = try!(visitor.visit()) {
vec.push(kv);
}
Ok(Content::Map(vec))
}
fn visit_enum<V>(self, _visitor: V) -> Result<Self::Value, V::Error>
where V: EnumVisitor
{
Err(de::Error::custom("untagged and internally tagged enums do not support enum input"))
}
}
/// This is the type of the map keys in an internally tagged enum.
///
/// Not public API.
pub enum TagOrContent {
Tag,
Content(Content),
}
struct TagOrContentVisitor {
name: &'static str,
}
impl TagOrContentVisitor {
fn new(name: &'static str) -> Self {
TagOrContentVisitor { name: name }
}
}
impl DeserializeSeed for TagOrContentVisitor {
type Value = TagOrContent;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where D: Deserializer
{
// Internally tagged enums are only supported in self-describing
// formats.
deserializer.deserialize(self)
}
}
impl Visitor for TagOrContentVisitor {
type Value = TagOrContent;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "a type tag `{}` or any other value", self.name)
}
fn visit_bool<F>(self, value: bool) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_bool(value).map(TagOrContent::Content)
}
fn visit_i8<F>(self, value: i8) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_i8(value).map(TagOrContent::Content)
}
fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_i16(value).map(TagOrContent::Content)
}
fn visit_i32<F>(self, value: i32) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_i32(value).map(TagOrContent::Content)
}
fn visit_i64<F>(self, value: i64) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_i64(value).map(TagOrContent::Content)
}
fn visit_u8<F>(self, value: u8) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_u8(value).map(TagOrContent::Content)
}
fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_u16(value).map(TagOrContent::Content)
}
fn visit_u32<F>(self, value: u32) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_u32(value).map(TagOrContent::Content)
}
fn visit_u64<F>(self, value: u64) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_u64(value).map(TagOrContent::Content)
}
fn visit_f32<F>(self, value: f32) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_f32(value).map(TagOrContent::Content)
}
fn visit_f64<F>(self, value: f64) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_f64(value).map(TagOrContent::Content)
}
fn visit_char<F>(self, value: char) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_char(value).map(TagOrContent::Content)
}
fn visit_str<F>(self, value: &str) -> Result<Self::Value, F>
where F: de::Error
{
if value == self.name {
Ok(TagOrContent::Tag)
} else {
ContentVisitor.visit_str(value).map(TagOrContent::Content)
}
}
fn visit_string<F>(self, value: String) -> Result<Self::Value, F>
where F: de::Error
{
if value == self.name {
Ok(TagOrContent::Tag)
} else {
ContentVisitor.visit_string(value).map(TagOrContent::Content)
}
}
fn visit_bytes<F>(self, value: &[u8]) -> Result<Self::Value, F>
where F: de::Error
{
if value == self.name.as_bytes() {
Ok(TagOrContent::Tag)
} else {
ContentVisitor.visit_bytes(value).map(TagOrContent::Content)
}
}
fn visit_byte_buf<F>(self, value: Vec<u8>) -> Result<Self::Value, F>
where F: de::Error
{
if value == self.name.as_bytes() {
Ok(TagOrContent::Tag)
} else {
ContentVisitor.visit_byte_buf(value).map(TagOrContent::Content)
}
}
fn visit_unit<F>(self) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_unit().map(TagOrContent::Content)
}
fn visit_none<F>(self) -> Result<Self::Value, F>
where F: de::Error
{
ContentVisitor.visit_none().map(TagOrContent::Content)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where D: Deserializer
{
ContentVisitor.visit_some(deserializer).map(TagOrContent::Content)
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where D: Deserializer
{
ContentVisitor.visit_newtype_struct(deserializer).map(TagOrContent::Content)
}
fn visit_seq<V>(self, visitor: V) -> Result<Self::Value, V::Error>
where V: SeqVisitor
{
ContentVisitor.visit_seq(visitor).map(TagOrContent::Content)
}
fn visit_map<V>(self, visitor: V) -> Result<Self::Value, V::Error>
where V: MapVisitor
{
ContentVisitor.visit_map(visitor).map(TagOrContent::Content)
}
fn visit_enum<V>(self, visitor: V) -> Result<Self::Value, V::Error>
where V: EnumVisitor
{
ContentVisitor.visit_enum(visitor).map(TagOrContent::Content)
}
}
/// Used by generated code to deserialize an internally tagged enum.
///
/// Not public API.
pub struct TaggedContent<T> {
pub tag: T,
pub content: Content,
}
/// Not public API.
pub struct TaggedContentVisitor<T> {
tag_name: &'static str,
tag: PhantomData<T>,
}
impl<T> TaggedContentVisitor<T> {
/// Visitor for the content of an internally tagged enum with the given tag
/// name.
pub fn new(name: &'static str) -> Self {
TaggedContentVisitor {
tag_name: name,
tag: PhantomData,
}
}
}
impl<T> DeserializeSeed for TaggedContentVisitor<T>
where T: Deserialize
{
type Value = TaggedContent<T>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where D: Deserializer
{
// Internally tagged enums are only supported in self-describing
// formats.
deserializer.deserialize(self)
}
}
impl<T> Visitor for TaggedContentVisitor<T>
where T: Deserialize
{
type Value = TaggedContent<T>;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("any value")
}
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where V: MapVisitor
{
let mut tag = None;
let mut vec = Vec::with_capacity(cmp::min(visitor.size_hint().0, 4096));
while let Some(k) = try!(visitor.visit_key_seed(TagOrContentVisitor::new(self.tag_name))) {
match k {
TagOrContent::Tag => {
if tag.is_some() {
return Err(de::Error::duplicate_field(self.tag_name));
}
tag = Some(try!(visitor.visit_value()));
}
TagOrContent::Content(k) => {
let v = try!(visitor.visit_value());
vec.push((k, v));
}
}
}
match tag {
None => Err(de::Error::missing_field(self.tag_name)),
Some(tag) => {
Ok(TaggedContent {
tag: tag,
content: Content::Map(vec),
})
}
}
}
}
/// Used by generated code to deserialize an adjacently tagged enum.
///
/// Not public API.
pub enum TagOrContentField {
Tag,
Content,
}
/// Not public API.
pub struct TagOrContentFieldVisitor {
pub tag: &'static str,
pub content: &'static str,
}
impl DeserializeSeed for TagOrContentFieldVisitor {
type Value = TagOrContentField;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where D: Deserializer
{
deserializer.deserialize_str(self)
}
}
impl Visitor for TagOrContentFieldVisitor {
type Value = TagOrContentField;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{:?} or {:?}", self.tag, self.content)
}
fn visit_str<E>(self, field: &str) -> Result<Self::Value, E>
where E: de::Error
{
if field == self.tag {
Ok(TagOrContentField::Tag)
} else if field == self.content {
Ok(TagOrContentField::Content)
} else {
Err(de::Error::invalid_value(Unexpected::Str(field), &self))
}
}
}
/// Not public API
pub struct ContentDeserializer<E> {
content: Content,
err: PhantomData<E>,
}
/// Used when deserializing an internally tagged enum because the content will
/// be used exactly once.
impl<E> Deserializer for ContentDeserializer<E>
where E: de::Error
{
type Error = E;
fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor
{
match self.content {
Content::Bool(v) => visitor.visit_bool(v),
Content::U8(v) => visitor.visit_u8(v),
Content::U16(v) => visitor.visit_u16(v),
Content::U32(v) => visitor.visit_u32(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I8(v) => visitor.visit_i8(v),
Content::I16(v) => visitor.visit_i16(v),
Content::I32(v) => visitor.visit_i32(v),
Content::I64(v) => visitor.visit_i64(v),
Content::F32(v) => visitor.visit_f32(v),
Content::F64(v) => visitor.visit_f64(v),
Content::Char(v) => visitor.visit_char(v),
Content::String(v) => visitor.visit_string(v),
Content::Unit => visitor.visit_unit(),
Content::None => visitor.visit_none(),
Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)),
Content::Newtype(v) => visitor.visit_newtype_struct(ContentDeserializer::new(*v)),
Content::Seq(v) => {
let seq = v.into_iter().map(ContentDeserializer::new);
let mut seq_visitor = de::value::SeqDeserializer::new(seq);
let value = try!(visitor.visit_seq(&mut seq_visitor));
try!(seq_visitor.end());
Ok(value)
}
Content::Map(v) => {
let map = v.into_iter()
.map(|(k, v)| (ContentDeserializer::new(k), ContentDeserializer::new(v)));
let mut map_visitor = de::value::MapDeserializer::new(map);
let value = try!(visitor.visit_map(&mut map_visitor));
try!(map_visitor.end());
Ok(value)
}
Content::Bytes(v) => visitor.visit_byte_buf(v),
}
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor
{
match self.content {
Content::None => visitor.visit_none(),
Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)),
Content::Unit => visitor.visit_unit(),
_ => visitor.visit_some(self),
}
}
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor
{
visitor.visit_newtype_struct(self)
}
forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct
struct_field tuple enum ignored_any
}
}
impl<E> ContentDeserializer<E> {
/// private API, don't use
pub fn new(content: Content) -> Self {
ContentDeserializer {
content: content,
err: PhantomData,
}
}
}
/// Not public API.
pub struct ContentRefDeserializer<'a, E> {
content: &'a Content,
err: PhantomData<E>,
}
/// Used when deserializing an untagged enum because the content may need to be
/// used more than once.
impl<'a, E> Deserializer for ContentRefDeserializer<'a, E>
where E: de::Error
{
type Error = E;
fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor
{
match *self.content {
Content::Bool(v) => visitor.visit_bool(v),
Content::U8(v) => visitor.visit_u8(v),
Content::U16(v) => visitor.visit_u16(v),
Content::U32(v) => visitor.visit_u32(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I8(v) => visitor.visit_i8(v),
Content::I16(v) => visitor.visit_i16(v),
Content::I32(v) => visitor.visit_i32(v),
Content::I64(v) => visitor.visit_i64(v),
Content::F32(v) => visitor.visit_f32(v),
Content::F64(v) => visitor.visit_f64(v),
Content::Char(v) => visitor.visit_char(v),
Content::String(ref v) => visitor.visit_str(v),
Content::Unit => visitor.visit_unit(),
Content::None => visitor.visit_none(),
Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)),
Content::Newtype(ref v) => visitor.visit_newtype_struct(ContentRefDeserializer::new(v)),
Content::Seq(ref v) => {
let seq = v.into_iter().map(ContentRefDeserializer::new);
let mut seq_visitor = de::value::SeqDeserializer::new(seq);
let value = try!(visitor.visit_seq(&mut seq_visitor));
try!(seq_visitor.end());
Ok(value)
}
Content::Map(ref v) => {
let map = v.into_iter().map(|&(ref k, ref v)| {
(ContentRefDeserializer::new(k), ContentRefDeserializer::new(v))
});
let mut map_visitor = de::value::MapDeserializer::new(map);
let value = try!(visitor.visit_map(&mut map_visitor));
try!(map_visitor.end());
Ok(value)
}
Content::Bytes(ref v) => visitor.visit_bytes(v),
}
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor
{
match *self.content {
Content::None => visitor.visit_none(),
Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)),
Content::Unit => visitor.visit_unit(),
_ => visitor.visit_some(self),
}
}
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor
{
visitor.visit_newtype_struct(self)
}
forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct
struct_field tuple enum ignored_any
}
}
impl<'a, E> ContentRefDeserializer<'a, E> {
/// private API, don't use
pub fn new(content: &'a Content) -> Self {
ContentRefDeserializer {
content: content,
err: PhantomData,
}
}
}
impl<E> de::value::ValueDeserializer<E> for ContentDeserializer<E>
where E: de::Error
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<'a, E> de::value::ValueDeserializer<E> for ContentRefDeserializer<'a, E>
where E: de::Error
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
/// Visitor for deserializing an internally tagged unit variant.
///
/// Not public API.
pub struct InternallyTaggedUnitVisitor<'a> {
type_name: &'a str,
variant_name: &'a str,
}
impl<'a> InternallyTaggedUnitVisitor<'a> {
/// Not public API.
pub fn new(type_name: &'a str, variant_name: &'a str) -> Self {
InternallyTaggedUnitVisitor {
type_name: type_name,
variant_name: variant_name,
}
}
}
impl<'a> Visitor for InternallyTaggedUnitVisitor<'a> {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name)
}
fn visit_map<V>(self, _: V) -> Result<(), V::Error>
where V: MapVisitor
{
Ok(())
}
}
/// Visitor for deserializing an untagged unit variant.
///
/// Not public API.
pub struct UntaggedUnitVisitor<'a> {
type_name: &'a str,
variant_name: &'a str,
}
impl<'a> UntaggedUnitVisitor<'a> {
/// Not public API.
pub fn new(type_name: &'a str, variant_name: &'a str) -> Self {
UntaggedUnitVisitor {
type_name: type_name,
variant_name: variant_name,
}
}
}
impl<'a> Visitor for UntaggedUnitVisitor<'a> {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name)
}
fn visit_unit<E>(self) -> Result<(), E>
where E: de::Error
{
Ok(())
}
}
+372 -375
View File
File diff suppressed because it is too large Load Diff
+1307 -526
View File
File diff suppressed because it is too large Load Diff
+44
View File
@@ -0,0 +1,44 @@
use core::marker::PhantomData;
use de::{Deserialize, Deserializer, Error, Visitor};
#[cfg(any(feature = "std", feature = "collections"))]
pub use de::content::{Content, ContentRefDeserializer, ContentDeserializer, TaggedContentVisitor,
TagOrContentField, TagOrContentFieldVisitor, InternallyTaggedUnitVisitor,
UntaggedUnitVisitor};
/// If the missing field is of type `Option<T>` then treat is as `None`,
/// otherwise it is an error.
pub fn missing_field<V, E>(field: &'static str) -> Result<V, E>
where V: Deserialize,
E: Error
{
struct MissingFieldDeserializer<E>(&'static str, PhantomData<E>);
impl<E> Deserializer for MissingFieldDeserializer<E>
where E: Error
{
type Error = E;
fn deserialize<V>(self, _visitor: V) -> Result<V::Value, E>
where V: Visitor
{
Err(Error::missing_field(self.0))
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, E>
where V: Visitor
{
visitor.visit_none()
}
forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
seq_fixed_size bytes byte_buf map unit_struct newtype_struct
tuple_struct struct struct_field tuple enum ignored_any
}
}
let deserializer = MissingFieldDeserializer(field, PhantomData);
Deserialize::deserialize(deserializer)
}
+481 -500
View File
File diff suppressed because it is too large Load Diff
+2 -29
View File
@@ -1,30 +1,7 @@
//! A stand-in for `std::error`
use core::any::TypeId;
use core::fmt::{Debug, Display};
/// A stand-in for `std::error::Error`, which requires no allocation.
#[cfg(feature = "unstable")]
pub trait Error: Debug + Display + ::core::marker::Reflect {
/// A short description of the error.
///
/// The description should not contain newlines or sentence-ending
/// punctuation, to facilitate embedding in larger user-facing
/// strings.
fn description(&self) -> &str;
/// The lower-level cause of this error, if any.
fn cause(&self) -> Option<&Error> { None }
/// Get the `TypeId` of `self`
#[doc(hidden)]
fn type_id(&self) -> TypeId where Self: 'static {
TypeId::of::<Self>()
}
}
/// A stand-in for `std::error::Error`, which requires no allocation.
#[cfg(not(feature = "unstable"))]
pub trait Error: Debug + Display {
/// A short description of the error.
///
@@ -34,11 +11,7 @@ pub trait Error: Debug + Display {
fn description(&self) -> &str;
/// The lower-level cause of this error, if any.
fn cause(&self) -> Option<&Error> { None }
/// Stubbed! Returns type_id of `()`
#[doc(hidden)]
fn type_id(&self) -> TypeId where Self: 'static {
TypeId::of::<()>()
fn cause(&self) -> Option<&Error> {
None
}
}
+34
View File
@@ -0,0 +1,34 @@
#[cfg(all(feature = "collections", not(feature = "std")))]
use collections::String;
#[cfg(feature = "std")]
use std::borrow::Cow;
#[cfg(all(feature = "collections", not(feature = "std")))]
use collections::borrow::Cow;
pub use core::default::Default;
pub use core::fmt;
pub use core::marker::PhantomData;
pub use core::option::Option::{self, None, Some};
pub use core::result::Result::{self, Ok, Err};
#[cfg(any(feature = "collections", feature = "std"))]
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> {
String::from_utf8_lossy(bytes)
}
// The generated code calls this like:
//
// let value = &_serde::export::from_utf8_lossy(bytes);
// Err(_serde::de::Error::unknown_variant(value, VARIANTS))
//
// so it is okay for the return type to be different from the std case as long
// as the above works.
#[cfg(not(any(feature = "collections", feature = "std")))]
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
use core::str;
// Three unicode replacement characters if it fails. They look like a
// white-on-black question mark. The user will recognize it as invalid
// UTF-8.
str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}")
}
+24 -12
View File
@@ -4,13 +4,13 @@ use std::io;
use std::iter::Peekable;
/// Iterator over a byte stream that tracks the current position's line and column.
pub struct LineColIterator<Iter: Iterator<Item=io::Result<u8>>> {
pub struct LineColIterator<Iter: Iterator<Item = io::Result<u8>>> {
iter: Iter,
line: usize,
col: usize,
}
impl<Iter: Iterator<Item=io::Result<u8>>> LineColIterator<Iter> {
impl<Iter: Iterator<Item = io::Result<u8>>> LineColIterator<Iter> {
/// Construct a new `LineColIterator<Iter>`.
pub fn new(iter: Iter) -> LineColIterator<Iter> {
LineColIterator {
@@ -21,27 +21,39 @@ impl<Iter: Iterator<Item=io::Result<u8>>> LineColIterator<Iter> {
}
/// Report the current line inside the iterator.
pub fn line(&self) -> usize { self.line }
pub fn line(&self) -> usize {
self.line
}
/// Report the current column inside the iterator.
pub fn col(&self) -> usize { self.col }
pub fn col(&self) -> usize {
self.col
}
/// Gets a reference to the underlying iterator.
pub fn get_ref(&self) -> &Iter { &self.iter }
pub fn get_ref(&self) -> &Iter {
&self.iter
}
/// Gets a mutable reference to the underlying iterator.
pub fn get_mut(&mut self) -> &mut Iter { &mut self.iter }
pub fn get_mut(&mut self) -> &mut Iter {
&mut self.iter
}
/// Unwraps this `LineColIterator`, returning the underlying iterator.
pub fn into_inner(self) -> Iter { self.iter }
pub fn into_inner(self) -> Iter {
self.iter
}
}
impl<Iter: Iterator<Item=io::Result<u8>>> LineColIterator<Peekable<Iter>> {
impl<Iter: Iterator<Item = io::Result<u8>>> LineColIterator<Peekable<Iter>> {
/// peeks at the next value
pub fn peek(&mut self) -> Option<&io::Result<u8>> { self.iter.peek() }
pub fn peek(&mut self) -> Option<&io::Result<u8>> {
self.iter.peek()
}
}
impl<Iter: Iterator<Item=io::Result<u8>>> Iterator for LineColIterator<Iter> {
impl<Iter: Iterator<Item = io::Result<u8>>> Iterator for LineColIterator<Iter> {
type Item = io::Result<u8>;
fn next(&mut self) -> Option<io::Result<u8>> {
match self.iter.next() {
@@ -50,11 +62,11 @@ impl<Iter: Iterator<Item=io::Result<u8>>> Iterator for LineColIterator<Iter> {
self.line += 1;
self.col = 0;
Some(Ok(b'\n'))
},
}
Some(Ok(c)) => {
self.col += 1;
Some(Ok(c))
},
}
Some(Err(e)) => Some(Err(e)),
}
}
+77 -28
View File
@@ -1,49 +1,93 @@
//! Serde Serialization Framework
//! # Serde
//!
//! Serde is a powerful framework that enables serialization libraries to generically serialize
//! Rust data structures without the overhead of runtime type information. In many situations, the
//! handshake protocol between serializers and serializees can be completely optimized away,
//! leaving serde to perform roughly the same speed as a hand written serializer for a specific
//! type.
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! For a detailed tutorial on the different ways to use serde please check out the
//! [github repository](https://github.com/serde-rs/serde)
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website https://serde.rs/ for additional documentation and
//! usage examples.
//!
//! ### Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's code
//! generation to automatically derive implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform roughly the same speed as a handwritten serializer
//! for the specific selection of data structure and data format.
//!
//! ### Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON](https://github.com/serde-rs/json), the ubiquitous JavaScript Object
//! Notation used by many HTTP APIs.
//! - [Bincode](https://github.com/TyOverby/bincode), a compact binary format
//! used for IPC within the Servo rendering engine.
//! - [CBOR](https://github.com/pyfisch/cbor), a Concise Binary Object
//! Representation designed for small message size without the need for
//! version negotiation.
//! - [YAML](https://github.com/dtolnay/serde-yaml), a popular human-friendly
//! configuration language that ain't markup language.
//! - [MessagePack](https://github.com/3Hren/msgpack-rust), an efficient binary
//! format that resembles a compact JSON.
//! - [TOML](https://github.com/alexcrichton/toml-rs), a minimal configuration
//! format used by [Cargo](http://doc.crates.io/manifest.html).
//! - [Pickle](https://github.com/birkenfeld/serde-pickle), a format common in
//! the Python world.
//! - [Hjson](https://github.com/laktak/hjson-rust), a variant of JSON designed
//! to be readable and writable by humans.
//! - [BSON](https://github.com/zonyitoo/bson-rs), the data storage and network
//! transfer format used by MongoDB.
//! - [URL](https://github.com/nox/serde_urlencoded), the x-www-form-urlencoded
//! format.
//! - [XML](https://github.com/serde-rs/xml), the flexible machine-friendly W3C
//! standard. *(deserialization only)*
//! - [Envy](https://github.com/softprops/envy), a way to deserialize
//! environment variables into Rust structs. *(deserialization only)*
//! - [Redis](https://github.com/OneSignal/serde-redis), deserialize values from
//! Redis when using [redis-rs](https://crates.io/crates/redis).
//! *(deserialization only)*
#![doc(html_root_url="https://docs.serde.rs")]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "unstable", feature(reflect_marker, unicode, nonzero, plugin, step_trait, zero_one))]
#![cfg_attr(feature = "unstable", feature(inclusive_range, nonzero, specialization, zero_one))]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(feature = "collections", feature(collections, enumset))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", allow(linkedlist))]
#![cfg_attr(any(not(feature = "std"), feature = "unstable"), allow(unused_variables, unused_imports, unused_features, dead_code))]
#![cfg_attr(feature = "collections", feature(collections))]
#![cfg_attr(feature = "cargo-clippy", allow(linkedlist, type_complexity, doc_markdown))]
#![deny(missing_docs)]
#[cfg(all(feature = "unstable", feature = "collections"))]
#[cfg(feature = "collections")]
extern crate collections;
#[cfg(all(feature = "unstable", feature = "alloc"))]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "unstable")]
extern crate core as actual_core;
#[cfg(feature = "std")]
mod core {
pub use std::{ops, hash, fmt, cmp, marker, mem, i8, i16, i32, i64, u8, u16, u32, u64, isize,
usize, f32, f64, char, str, num, slice, iter};
usize, f32, f64, char, str, num, slice, iter, cell, default, result, option};
#[cfg(feature = "unstable")]
extern crate core;
#[cfg(feature = "unstable")]
pub use self::core::nonzero;
pub use actual_core::nonzero;
}
#[doc(inline)]
pub use ser::{Serialize, Serializer};
pub use de::{Deserialize, Deserializer, Error};
#[cfg(not(feature = "std"))]
macro_rules! format {
($s:expr, $($rest:tt)*) => ($s)
}
#[doc(inline)]
pub use de::{Deserialize, Deserializer};
#[macro_use]
mod macros;
@@ -51,8 +95,13 @@ mod macros;
pub mod bytes;
pub mod de;
#[cfg(feature = "std")]
#[doc(hidden)]
pub mod iter;
pub mod ser;
#[cfg(not(feature = "std"))]
#[cfg_attr(feature = "std", doc(hidden))]
pub mod error;
mod utils;
// Generated code uses these to support no_std. Not public API.
#[doc(hidden)]
pub mod export;
+92 -49
View File
@@ -4,7 +4,7 @@
macro_rules! forward_to_deserialize_method {
($func:ident($($arg:ty),*)) => {
#[inline]
fn $func<__V>(&mut self, $(_: $arg,)* visitor: __V) -> ::std::result::Result<__V::Value, Self::Error>
fn $func<__V>(self, $(_: $arg,)* visitor: __V) -> ::std::result::Result<__V::Value, Self::Error>
where __V: $crate::de::Visitor
{
self.deserialize(visitor)
@@ -18,7 +18,7 @@ macro_rules! forward_to_deserialize_method {
macro_rules! forward_to_deserialize_method {
($func:ident($($arg:ty),*)) => {
#[inline]
fn $func<__V>(&mut self, $(_: $arg,)* visitor: __V) -> ::core::result::Result<__V::Value, Self::Error>
fn $func<__V>(self, $(_: $arg,)* visitor: __V) -> ::core::result::Result<__V::Value, Self::Error>
where __V: $crate::de::Visitor
{
self.deserialize(visitor)
@@ -26,43 +26,12 @@ macro_rules! forward_to_deserialize_method {
};
}
#[cfg(feature = "std")]
#[doc(hidden)]
#[macro_export]
macro_rules! forward_to_deserialize_enum {
() => {
#[inline]
fn deserialize_enum<__V>(&mut self, _: &str, _: &[&str], _: __V) -> ::std::result::Result<__V::Value, Self::Error>
where __V: $crate::de::EnumVisitor
{
Err($crate::de::Error::invalid_type($crate::de::Type::Enum))
}
};
}
#[cfg(not(feature = "std"))]
#[doc(hidden)]
#[macro_export]
macro_rules! forward_to_deserialize_enum {
() => {
#[inline]
fn deserialize_enum<__V>(&mut self, _: &str, _: &[&str], _: __V) -> ::core::result::Result<__V::Value, Self::Error>
where __V: $crate::de::EnumVisitor
{
Err($crate::de::Error::invalid_type($crate::de::Type::Enum))
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! forward_to_deserialize_helper {
(bool) => {
forward_to_deserialize_method!{deserialize_bool()}
};
(usize) => {
forward_to_deserialize_method!{deserialize_usize()}
};
(u8) => {
forward_to_deserialize_method!{deserialize_u8()}
};
@@ -75,9 +44,6 @@ macro_rules! forward_to_deserialize_helper {
(u64) => {
forward_to_deserialize_method!{deserialize_u64()}
};
(isize) => {
forward_to_deserialize_method!{deserialize_isize()}
};
(i8) => {
forward_to_deserialize_method!{deserialize_i8()}
};
@@ -120,6 +86,9 @@ macro_rules! forward_to_deserialize_helper {
(bytes) => {
forward_to_deserialize_method!{deserialize_bytes()}
};
(byte_buf) => {
forward_to_deserialize_method!{deserialize_byte_buf()}
};
(map) => {
forward_to_deserialize_method!{deserialize_map()}
};
@@ -141,39 +110,113 @@ macro_rules! forward_to_deserialize_helper {
(tuple) => {
forward_to_deserialize_method!{deserialize_tuple(usize)}
};
(enum) => {
forward_to_deserialize_method!{deserialize_enum(&'static str, &'static [&'static str])}
};
(ignored_any) => {
forward_to_deserialize_method!{deserialize_ignored_any()}
};
(enum) => {
forward_to_deserialize_enum!();
};
}
/// Helper to forward `Deserializer` methods to `Deserializer::deserialize`.
/// Every given method ignores all arguments and forwards to `deserialize`.
/// Note that `deserialize_enum` simply returns an `Error::invalid_type`; a
/// better approach is tracked in [serde-rs/serde#521][1].
// Super explicit first paragraph because this shows up at the top level and
// trips up people who are just looking for basic Serialize / Deserialize
// documentation.
//
/// Helper macro when implementing the `Deserializer` part of a new data format
/// for Serde.
///
/// ```rust,ignore
/// Some `Deserializer` implementations for self-describing formats do not care
/// what hint the `Visitor` gives them, they just want to blindly call the
/// `Visitor` method corresponding to the data they can tell is in the input.
/// This requires repetitive implementations of all the `Deserializer` trait
/// methods.
///
/// ```rust
/// # #[macro_use] extern crate serde;
/// # use serde::de::{value, Deserializer, Visitor};
/// # pub struct MyDeserializer;
/// # impl Deserializer for MyDeserializer {
/// # type Error = value::Error;
/// # fn deserialize<V>(self, _: V) -> Result<V::Value, Self::Error>
/// # where V: Visitor
/// # { unimplemented!() }
/// #
/// #[inline]
/// fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
/// where V: Visitor
/// {
/// self.deserialize(visitor)
/// }
/// # forward_to_deserialize! {
/// # u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
/// # seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
/// # tuple_struct struct struct_field tuple enum ignored_any
/// # }
/// # }
/// # fn main() {}
/// ```
///
/// The `forward_to_deserialize!` macro implements these simple forwarding
/// methods so that they forward directly to `Deserializer::deserialize`. You
/// can choose which methods to forward.
///
/// ```rust
/// # #[macro_use] extern crate serde;
/// # use serde::de::{value, Deserializer, Visitor};
/// # pub struct MyDeserializer;
/// impl Deserializer for MyDeserializer {
/// fn deserialize<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error>
/// # type Error = value::Error;
/// fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
/// where V: Visitor
/// {
/// /* ... */
/// # let _ = visitor;
/// # unimplemented!()
/// }
///
/// forward_to_deserialize! {
/// bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string
/// unit option seq seq_fixed_size bytes map unit_struct newtype_struct
/// bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
/// seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
/// tuple_struct struct struct_field tuple enum ignored_any
/// }
/// }
/// # fn main() {}
/// ```
///
/// [1]: https://github.com/serde-rs/serde/issues/521
#[macro_export]
macro_rules! forward_to_deserialize {
($($func:ident)*) => {
$(forward_to_deserialize_helper!{$func})*
};
}
/// Seralize the `$value` that implements Display as a string,
/// when that string is statically known to never have more than
/// a constant `$MAX_LEN` bytes.
///
/// Panics if the Display impl tries to write more than `$MAX_LEN` bytes.
#[cfg(feature = "std")]
// Not exported
macro_rules! serialize_display_bounded_length {
($value: expr, $MAX_LEN: expr, $serializer: expr) => {
{
use std::io::Write;
let mut buffer: [u8; $MAX_LEN] = unsafe { ::std::mem::uninitialized() };
let remaining_len;
{
let mut remaining = &mut buffer[..];
write!(remaining, "{}", $value).unwrap();
remaining_len = remaining.len()
}
let written_len = buffer.len() - remaining_len;
let written = &buffer[..written_len];
// write! only provides std::fmt::Formatter to Display implementations,
// which has methods write_str and write_char but no method to write arbitrary bytes.
// Therefore, `written` is well-formed in UTF-8.
let written_str = unsafe {
::std::str::from_utf8_unchecked(written)
};
$serializer.serialize_str(written_str)
}
}
}
+161 -163
View File
@@ -1,48 +1,23 @@
//! Implementations for all of Rust's builtin types. Tuples implement the `Serialize` trait if they
//! have at most 16 fields. Arrays implement the `Serialize` trait if their length is 32 or less.
//! You can always forward array serialization to slice serialization, which works for any length.
//! Long tuples are best replaced by tuple structs, for which you can use `derive(Serialize)`. In
//! that case the number of fields is irrelevant.
#[cfg(feature = "std")]
use std::borrow::Cow;
#[cfg(all(feature = "collections", not(feature = "std")))]
use collections::borrow::Cow;
#[cfg(feature = "std")]
use std::collections::{
BinaryHeap,
BTreeMap,
BTreeSet,
LinkedList,
HashMap,
HashSet,
VecDeque,
};
use std::collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, HashMap, HashSet, VecDeque};
#[cfg(all(feature = "collections", not(feature = "std")))]
use collections::{
BinaryHeap,
BTreeMap,
BTreeSet,
LinkedList,
VecDeque,
String,
Vec,
};
use collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque, String, Vec};
#[cfg(all(feature = "unstable", feature = "collections"))]
use collections::enum_set::{CLike, EnumSet};
#[cfg(all(feature = "unstable", feature = "collections"))]
#[cfg(feature = "collections")]
use collections::borrow::ToOwned;
#[cfg(feature = "std")]
use core::hash::{Hash, BuildHasher};
#[cfg(feature = "unstable")]
use core::iter;
#[cfg(feature = "std")]
use std::net;
#[cfg(feature = "unstable")]
use core::num;
#[cfg(feature = "unstable")]
use core::ops;
#[cfg(feature = "std")]
use std::path;
@@ -66,34 +41,32 @@ use core::marker::PhantomData;
#[cfg(feature = "unstable")]
use core::nonzero::{NonZero, Zeroable};
use super::{
Error,
Serialize,
Serializer,
};
use super::{Serialize, SerializeSeq, SerializeTuple, Serializer};
#[cfg(feature = "std")]
use super::Error;
///////////////////////////////////////////////////////////////////////////////
macro_rules! impl_visit {
($ty:ty, $method:ident) => {
($ty:ty, $method:ident $($cast:tt)*) => {
impl Serialize for $ty {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
serializer.$method(*self)
serializer.$method(*self $($cast)*)
}
}
}
}
impl_visit!(bool, serialize_bool);
impl_visit!(isize, serialize_isize);
impl_visit!(isize, serialize_i64 as i64);
impl_visit!(i8, serialize_i8);
impl_visit!(i16, serialize_i16);
impl_visit!(i32, serialize_i32);
impl_visit!(i64, serialize_i64);
impl_visit!(usize, serialize_usize);
impl_visit!(usize, serialize_u64 as u64);
impl_visit!(u8, serialize_u8);
impl_visit!(u16, serialize_u16);
impl_visit!(u32, serialize_u32);
@@ -106,8 +79,8 @@ impl_visit!(char, serialize_char);
impl Serialize for str {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_str(self)
}
@@ -116,8 +89,8 @@ impl Serialize for str {
#[cfg(any(feature = "std", feature = "collections"))]
impl Serialize for String {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
(&self[..]).serialize(serializer)
}
@@ -125,10 +98,12 @@ impl Serialize for String {
///////////////////////////////////////////////////////////////////////////////
impl<T> Serialize for Option<T> where T: Serialize {
impl<T> Serialize for Option<T>
where T: Serialize
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
match *self {
Some(ref value) => serializer.serialize_some(value),
@@ -141,45 +116,27 @@ impl<T> Serialize for Option<T> where T: Serialize {
impl<T> Serialize for PhantomData<T> {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_unit_struct("PhantomData")
}
}
///////////////////////////////////////////////////////////////////////////////
impl<T> Serialize for [T]
where T: Serialize,
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
{
let mut state = try!(serializer.serialize_seq(Some(self.len())));
for e in self {
try!(serializer.serialize_seq_elt(&mut state, e));
}
serializer.serialize_seq_end(state)
}
}
///////////////////////////////////////////////////////////////////////////////
macro_rules! array_impls {
($len:expr) => {
impl<T> Serialize for [T; $len] where T: Serialize {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
let mut state = try!(serializer.serialize_seq_fixed_size($len));
let mut seq = try!(serializer.serialize_seq_fixed_size($len));
for e in self {
try!(serializer.serialize_seq_elt(&mut state, e));
try!(seq.serialize_element(e));
}
serializer.serialize_seq_end(state)
seq.end()
}
}
}
@@ -224,18 +181,20 @@ array_impls!(32);
macro_rules! serialize_seq {
() => {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
let mut state = try!(serializer.serialize_seq(Some(self.len())));
for e in self {
try!(serializer.serialize_seq_elt(&mut state, e));
}
serializer.serialize_seq_end(state)
serializer.collect_seq(self)
}
}
}
impl<T> Serialize for [T]
where T: Serialize
{
serialize_seq!();
}
#[cfg(any(feature = "std", feature = "collections"))]
impl<T> Serialize for BinaryHeap<T>
where T: Serialize + Ord
@@ -245,14 +204,7 @@ impl<T> Serialize for BinaryHeap<T>
#[cfg(any(feature = "std", feature = "collections"))]
impl<T> Serialize for BTreeSet<T>
where T: Serialize + Ord,
{
serialize_seq!();
}
#[cfg(all(feature = "unstable", feature = "collections"))]
impl<T> Serialize for EnumSet<T>
where T: Serialize + CLike
where T: Serialize + Ord
{
serialize_seq!();
}
@@ -260,43 +212,63 @@ impl<T> Serialize for EnumSet<T>
#[cfg(feature = "std")]
impl<T, H> Serialize for HashSet<T, H>
where T: Serialize + Eq + Hash,
H: BuildHasher,
H: BuildHasher
{
serialize_seq!();
}
#[cfg(any(feature = "std", feature = "collections"))]
impl<T> Serialize for LinkedList<T>
where T: Serialize,
where T: Serialize
{
serialize_seq!();
}
#[cfg(any(feature = "std", feature = "collections"))]
impl<T> Serialize for Vec<T> where T: Serialize {
impl<T> Serialize for Vec<T>
where T: Serialize
{
serialize_seq!();
}
#[cfg(any(feature = "std", feature = "collections"))]
impl<T> Serialize for VecDeque<T> where T: Serialize {
impl<T> Serialize for VecDeque<T>
where T: Serialize
{
serialize_seq!();
}
#[cfg(feature = "unstable")]
impl<A> Serialize for ops::Range<A>
where A: Serialize + Clone + iter::Step + num::One,
for<'a> &'a A: ops::Add<&'a A, Output = A>,
where ops::Range<A>: ExactSizeIterator + iter::Iterator<Item = A> + Clone,
A: Serialize
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let len = iter::Step::steps_between(&self.start, &self.end, &A::one());
let mut state = try!(serializer.serialize_seq(len));
let mut seq = try!(serializer.serialize_seq(Some(self.len())));
for e in self.clone() {
try!(serializer.serialize_seq_elt(&mut state, e));
try!(seq.serialize_element(&e));
}
serializer.serialize_seq_end(state)
seq.end()
}
}
#[cfg(feature = "unstable")]
impl<A> Serialize for ops::RangeInclusive<A>
where ops::RangeInclusive<A>: ExactSizeIterator + iter::Iterator<Item = A> + Clone,
A: Serialize
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let mut seq = try!(serializer.serialize_seq(Some(self.len())));
for e in self.clone() {
try!(seq.serialize_element(&e));
}
seq.end()
}
}
@@ -304,8 +276,8 @@ impl<A> Serialize for ops::Range<A>
impl Serialize for () {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_unit()
}
@@ -324,14 +296,14 @@ macro_rules! tuple_impls {
where $($T: Serialize),+
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
let mut state = try!(serializer.serialize_tuple($len));
let mut tuple = try!(serializer.serialize_tuple($len));
$(
try!(serializer.serialize_tuple_elt(&mut state, &self.$idx));
try!(tuple.serialize_element(&self.$idx));
)+
serializer.serialize_tuple_end(state)
tuple.end()
}
}
)+
@@ -514,15 +486,10 @@ tuple_impls! {
macro_rules! serialize_map {
() => {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
let mut state = try!(serializer.serialize_map(Some(self.len())));
for (k, v) in self {
try!(serializer.serialize_map_key(&mut state, k));
try!(serializer.serialize_map_value(&mut state, v));
}
serializer.serialize_map_end(state)
serializer.collect_map(self)
}
}
}
@@ -530,7 +497,7 @@ macro_rules! serialize_map {
#[cfg(any(feature = "std", feature = "collections"))]
impl<K, V> Serialize for BTreeMap<K, V>
where K: Serialize + Ord,
V: Serialize,
V: Serialize
{
serialize_map!();
}
@@ -539,66 +506,78 @@ impl<K, V> Serialize for BTreeMap<K, V>
impl<K, V, H> Serialize for HashMap<K, V, H>
where K: Serialize + Eq + Hash,
V: Serialize,
H: BuildHasher,
H: BuildHasher
{
serialize_map!();
}
///////////////////////////////////////////////////////////////////////////////
impl<'a, T: ?Sized> Serialize for &'a T where T: Serialize {
impl<'a, T: ?Sized> Serialize for &'a T
where T: Serialize
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
(**self).serialize(serializer)
}
}
impl<'a, T: ?Sized> Serialize for &'a mut T where T: Serialize {
impl<'a, T: ?Sized> Serialize for &'a mut T
where T: Serialize
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
(**self).serialize(serializer)
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T: ?Sized> Serialize for Box<T> where T: Serialize {
impl<T: ?Sized> Serialize for Box<T>
where T: Serialize
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
(**self).serialize(serializer)
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T> Serialize for Rc<T> where T: Serialize, {
impl<T> Serialize for Rc<T>
where T: Serialize
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
(**self).serialize(serializer)
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T> Serialize for Arc<T> where T: Serialize, {
impl<T> Serialize for Arc<T>
where T: Serialize
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
(**self).serialize(serializer)
}
}
#[cfg(any(feature = "std", feature = "collections"))]
impl<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned, {
impl<'a, T: ?Sized> Serialize for Cow<'a, T>
where T: Serialize + ToOwned
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
(**self).serialize(serializer)
}
@@ -606,12 +585,15 @@ impl<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned, {
///////////////////////////////////////////////////////////////////////////////
impl<T, E> Serialize for Result<T, E> where T: Serialize, E: Serialize {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
impl<T, E> Serialize for Result<T, E>
where T: Serialize,
E: Serialize
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
match *self {
Result::Ok(ref value) => {
serializer.serialize_newtype_variant("Result", 0, "Ok", value)
}
Result::Ok(ref value) => serializer.serialize_newtype_variant("Result", 0, "Ok", value),
Result::Err(ref value) => {
serializer.serialize_newtype_variant("Result", 1, "Err", value)
}
@@ -623,13 +605,14 @@ impl<T, E> Serialize for Result<T, E> where T: Serialize, E: Serialize {
#[cfg(feature = "std")]
impl Serialize for Duration {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
use super::SerializeStruct;
let mut state = try!(serializer.serialize_struct("Duration", 2));
try!(serializer.serialize_struct_elt(&mut state, "secs", self.as_secs()));
try!(serializer.serialize_struct_elt(&mut state, "nanos", self.subsec_nanos()));
serializer.serialize_struct_end(state)
try!(state.serialize_field("secs", &self.as_secs()));
try!(state.serialize_field("nanos", &self.subsec_nanos()));
state.end()
}
}
@@ -637,28 +620,35 @@ impl Serialize for Duration {
#[cfg(feature = "std")]
impl Serialize for net::IpAddr {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
self.to_string().serialize(serializer)
match *self {
net::IpAddr::V4(ref a) => a.serialize(serializer),
net::IpAddr::V6(ref a) => a.serialize(serializer),
}
}
}
#[cfg(feature = "std")]
impl Serialize for net::Ipv4Addr {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
self.to_string().serialize(serializer)
/// "101.102.103.104".len()
const MAX_LEN: usize = 15;
serialize_display_bounded_length!(self, MAX_LEN, serializer)
}
}
#[cfg(feature = "std")]
impl Serialize for net::Ipv6Addr {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
self.to_string().serialize(serializer)
/// "1000:1002:1003:1004:1005:1006:1007:1008".len()
const MAX_LEN: usize = 39;
serialize_display_bounded_length!(self, MAX_LEN, serializer)
}
}
@@ -666,8 +656,8 @@ impl Serialize for net::Ipv6Addr {
#[cfg(feature = "std")]
impl Serialize for net::SocketAddr {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
match *self {
net::SocketAddr::V4(ref addr) => addr.serialize(serializer),
@@ -678,19 +668,23 @@ impl Serialize for net::SocketAddr {
#[cfg(feature = "std")]
impl Serialize for net::SocketAddrV4 {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
self.to_string().serialize(serializer)
/// "101.102.103.104:65000".len()
const MAX_LEN: usize = 21;
serialize_display_bounded_length!(self, MAX_LEN, serializer)
}
}
#[cfg(feature = "std")]
impl Serialize for net::SocketAddrV6 {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
self.to_string().serialize(serializer)
/// "[1000:1002:1003:1004:1005:1006:1007:1008]:65000".len()
const MAX_LEN: usize = 47;
serialize_display_bounded_length!(self, MAX_LEN, serializer)
}
}
@@ -698,28 +692,32 @@ impl Serialize for net::SocketAddrV6 {
#[cfg(feature = "std")]
impl Serialize for path::Path {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
match self.to_str() {
Some(s) => s.serialize(serializer),
None => Err(Error::invalid_value("Path contains invalid UTF-8 characters")),
None => Err(Error::custom("path contains invalid UTF-8 characters")),
}
}
}
#[cfg(feature = "std")]
impl Serialize for path::PathBuf {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
self.as_path().serialize(serializer)
}
}
#[cfg(feature = "unstable")]
impl<T> Serialize for NonZero<T> where T: Serialize + Zeroable {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
impl<T> Serialize for NonZero<T>
where T: Serialize + Zeroable
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
(**self).serialize(serializer)
}
}
+156
View File
@@ -0,0 +1,156 @@
//! This module contains `Impossible` serializer and its implementations.
use core::marker::PhantomData;
use ser::{self, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct,
SerializeTupleVariant, SerializeMap, SerializeStruct, SerializeStructVariant};
/// Helper type for implementing a `Serializer` that does not support
/// serializing one of the compound types.
///
/// This type cannot be instantiated, but implements every one of the traits
/// corresponding to the `Serializer` compound types: `SerializeSeq`,
/// `SerializeTuple`, `SerializeTupleStruct`, `SerializeTupleVariant`,
/// `SerializeMap`, `SerializeStruct`, and `SerializeStructVariant`.
///
/// ```rust,ignore
/// impl Serializer for MySerializer {
/// type Ok = ();
/// type Error = Error;
///
/// type SerializeSeq = Impossible<(), Error>;
/// /* other associated types */
///
/// /// This data format does not support serializing sequences.
/// fn serialize_seq(self,
/// len: Option<usize>)
/// -> Result<Self::SerializeSeq, Error> {
/// // Given Impossible cannot be instantiated, the only
/// // thing we can do here is to return an error.
/// Err(...)
/// }
///
/// /* other Serializer methods */
/// }
/// ```
pub struct Impossible<Ok, E> {
void: Void,
_marker: PhantomData<(Ok, E)>,
}
enum Void {}
impl<Ok, E> SerializeSeq for Impossible<Ok, E>
where E: ser::Error
{
type Ok = Ok;
type Error = E;
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
match self.void {}
}
fn end(self) -> Result<Ok, E> {
match self.void {}
}
}
impl<Ok, E> SerializeTuple for Impossible<Ok, E>
where E: ser::Error
{
type Ok = Ok;
type Error = E;
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
match self.void {}
}
fn end(self) -> Result<Ok, E> {
match self.void {}
}
}
impl<Ok, E> SerializeTupleStruct for Impossible<Ok, E>
where E: ser::Error
{
type Ok = Ok;
type Error = E;
fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
match self.void {}
}
fn end(self) -> Result<Ok, E> {
match self.void {}
}
}
impl<Ok, E> SerializeTupleVariant for Impossible<Ok, E>
where E: ser::Error
{
type Ok = Ok;
type Error = E;
fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
match self.void {}
}
fn end(self) -> Result<Ok, E> {
match self.void {}
}
}
impl<Ok, E> SerializeMap for Impossible<Ok, E>
where E: ser::Error
{
type Ok = Ok;
type Error = E;
fn serialize_key<T: ?Sized + Serialize>(&mut self, _key: &T) -> Result<(), E> {
match self.void {}
}
fn serialize_value<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
match self.void {}
}
fn end(self) -> Result<Ok, E> {
match self.void {}
}
}
impl<Ok, E> SerializeStruct for Impossible<Ok, E>
where E: ser::Error
{
type Ok = Ok;
type Error = E;
fn serialize_field<T: ?Sized + Serialize>(&mut self,
_key: &'static str,
_value: &T)
-> Result<(), E> {
match self.void {}
}
fn end(self) -> Result<Ok, E> {
match self.void {}
}
}
impl<Ok, E> SerializeStructVariant for Impossible<Ok, E>
where E: ser::Error
{
type Ok = Ok;
type Error = E;
fn serialize_field<T: ?Sized + Serialize>(&mut self,
_key: &'static str,
_value: &T)
-> Result<(), E> {
match self.void {}
}
fn end(self) -> Result<Ok, E> {
match self.void {}
}
}
+781 -347
View File
File diff suppressed because it is too large Load Diff
+262
View File
@@ -0,0 +1,262 @@
use core::fmt::{self, Display};
use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct};
/// Not public API.
pub fn serialize_tagged_newtype<S, T>(serializer: S,
type_ident: &'static str,
variant_ident: &'static str,
tag: &'static str,
variant_name: &'static str,
value: T)
-> Result<S::Ok, S::Error>
where S: Serializer,
T: Serialize
{
value.serialize(TaggedSerializer {
type_ident: type_ident,
variant_ident: variant_ident,
tag: tag,
variant_name: variant_name,
delegate: serializer,
})
}
struct TaggedSerializer<S> {
type_ident: &'static str,
variant_ident: &'static str,
tag: &'static str,
variant_name: &'static str,
delegate: S,
}
enum Unsupported {
Boolean,
Integer,
Float,
Char,
String,
ByteArray,
Optional,
Unit,
UnitStruct,
Sequence,
Tuple,
TupleStruct,
Enum,
}
impl Display for Unsupported {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
Unsupported::Boolean => formatter.write_str("a boolean"),
Unsupported::Integer => formatter.write_str("an integer"),
Unsupported::Float => formatter.write_str("a float"),
Unsupported::Char => formatter.write_str("a char"),
Unsupported::String => formatter.write_str("a string"),
Unsupported::ByteArray => formatter.write_str("a byte array"),
Unsupported::Optional => formatter.write_str("an optional"),
Unsupported::Unit => formatter.write_str("unit"),
Unsupported::UnitStruct => formatter.write_str("a unit struct"),
Unsupported::Sequence => formatter.write_str("a sequence"),
Unsupported::Tuple => formatter.write_str("a tuple"),
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
Unsupported::Enum => formatter.write_str("an enum"),
}
}
}
struct Error {
type_ident: &'static str,
variant_ident: &'static str,
ty: Unsupported,
}
impl Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter,
"cannot serialize tagged newtype variant {}::{} containing {}",
self.type_ident, self.variant_ident, self.ty)
}
}
impl<S> TaggedSerializer<S>
where S: Serializer
{
fn bad_type(self, what: Unsupported) -> S::Error {
ser::Error::custom(Error {
type_ident: self.type_ident,
variant_ident: self.variant_ident,
ty: what,
})
}
}
impl<S> Serializer for TaggedSerializer<S>
where S: Serializer
{
type Ok = S::Ok;
type Error = S::Error;
type SerializeSeq = S::SerializeSeq;
type SerializeTuple = S::SerializeTuple;
type SerializeTupleStruct = S::SerializeTupleStruct;
type SerializeTupleVariant = S::SerializeTupleVariant;
type SerializeMap = S::SerializeMap;
type SerializeStruct = S::SerializeStruct;
type SerializeStructVariant = S::SerializeStructVariant;
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Boolean))
}
fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Float))
}
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Float))
}
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Char))
}
fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::String))
}
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::ByteArray))
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Optional))
}
fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
where T: Serialize
{
Err(self.bad_type(Unsupported::Optional))
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Unit))
}
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::UnitStruct))
}
fn serialize_unit_variant(self,
_: &'static str,
_: usize,
_: &'static str)
-> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Enum))
}
fn serialize_newtype_struct<T: ?Sized>(self,
_: &'static str,
value: &T)
-> Result<Self::Ok, Self::Error>
where T: Serialize
{
value.serialize(self)
}
fn serialize_newtype_variant<T: ?Sized>(self,
_: &'static str,
_: usize,
_: &'static str,
_: &T)
-> Result<Self::Ok, Self::Error>
where T: Serialize
{
Err(self.bad_type(Unsupported::Enum))
}
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Err(self.bad_type(Unsupported::Sequence))
}
fn serialize_seq_fixed_size(self, _: usize) -> Result<Self::SerializeSeq, Self::Error> {
Err(self.bad_type(Unsupported::Sequence))
}
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
Err(self.bad_type(Unsupported::Tuple))
}
fn serialize_tuple_struct(self,
_: &'static str,
_: usize)
-> Result<Self::SerializeTupleStruct, Self::Error> {
Err(self.bad_type(Unsupported::TupleStruct))
}
fn serialize_tuple_variant(self,
_: &'static str,
_: usize,
_: &'static str,
_: usize)
-> Result<Self::SerializeTupleVariant, Self::Error> {
Err(self.bad_type(Unsupported::Enum))
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
let mut map = try!(self.delegate.serialize_map(len.map(|len| len + 1)));
try!(map.serialize_entry(self.tag, self.variant_name));
Ok(map)
}
fn serialize_struct(self,
name: &'static str,
len: usize)
-> Result<Self::SerializeStruct, Self::Error> {
let mut state = try!(self.delegate.serialize_struct(name, len + 1));
try!(state.serialize_field(self.tag, self.variant_name));
Ok(state)
}
fn serialize_struct_variant(self,
_: &'static str,
_: usize,
_: &'static str,
_: usize)
-> Result<Self::SerializeStructVariant, Self::Error> {
Err(self.bad_type(Unsupported::Enum))
}
}
+20 -18
View File
@@ -1,12 +1,12 @@
//! Private utility functions
const TAG_CONT: u8 = 0b1000_0000;
const TAG_TWO_B: u8 = 0b1100_0000;
const TAG_CONT: u8 = 0b1000_0000;
const TAG_TWO_B: u8 = 0b1100_0000;
const TAG_THREE_B: u8 = 0b1110_0000;
const TAG_FOUR_B: u8 = 0b1111_0000;
const MAX_ONE_B: u32 = 0x80;
const MAX_TWO_B: u32 = 0x800;
const MAX_THREE_B: u32 = 0x10000;
const TAG_FOUR_B: u8 = 0b1111_0000;
const MAX_ONE_B: u32 = 0x80;
const MAX_TWO_B: u32 = 0x800;
const MAX_THREE_B: u32 = 0x10000;
#[inline]
pub fn encode_utf8(c: char) -> EncodeUtf8 {
@@ -21,17 +21,20 @@ pub fn encode_utf8(c: char) -> EncodeUtf8 {
2
} else if code < MAX_THREE_B {
buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
1
} else {
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
0
};
EncodeUtf8 { buf: buf, pos: pos }
EncodeUtf8 {
buf: buf,
pos: pos,
}
}
pub struct EncodeUtf8 {
@@ -47,23 +50,22 @@ impl EncodeUtf8 {
}
#[allow(non_upper_case_globals)]
const Pattern_White_Space_table: &'static [(char, char)] = &[
('\u{9}', '\u{d}'), ('\u{20}', '\u{20}'), ('\u{85}', '\u{85}'), ('\u{200e}', '\u{200f}'),
('\u{2028}', '\u{2029}')
];
const Pattern_White_Space_table: &'static [(char, char)] = &[('\u{9}', '\u{d}'),
('\u{20}', '\u{20}'),
('\u{85}', '\u{85}'),
('\u{200e}', '\u{200f}'),
('\u{2028}', '\u{2029}')];
fn bsearch_range_table(c: char, r: &'static [(char, char)]) -> bool {
use core::cmp::Ordering::{Equal, Less, Greater};
r.binary_search_by(|&(lo, hi)| {
if c < lo {
r.binary_search_by(|&(lo, hi)| if c < lo {
Greater
} else if hi < c {
Less
} else {
Equal
}
})
.is_ok()
})
.is_ok()
}
#[allow(non_snake_case)]
-29
View File
@@ -1,29 +0,0 @@
[package]
name = "serde_codegen"
version = "0.8.22"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://serde.rs/codegen.html"
keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
[features]
default = ["with-syntex"]
unstable = []
unstable-testing = ["clippy"]
with-syntex = [
"syntex",
"syntex_syntax",
]
with-syn = []
[dependencies]
clippy = { version = "^0.*", optional = true }
quote = "0.3.8"
serde_codegen_internals = { version = "=0.11.3", default-features = false, path = "../serde_codegen_internals" }
syn = { version = "0.10", features = ["aster", "visit"] }
syntex = { version = "^0.54.0", optional = true }
syntex_syntax = { version = "^0.54.0", optional = true }
-121
View File
@@ -1,121 +0,0 @@
use std::collections::HashSet;
use syn::{self, aster, visit};
use internals::ast::Item;
use internals::attr;
// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
// allowed here".
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
syn::Generics {
ty_params: generics.ty_params.iter().map(|ty_param| {
syn::TyParam {
default: None,
.. ty_param.clone()
}}).collect(),
.. generics.clone()
}
}
pub fn with_where_predicates(
generics: &syn::Generics,
predicates: &[syn::WherePredicate],
) -> syn::Generics {
aster::from_generics(generics.clone())
.with_predicates(predicates.to_vec())
.build()
}
pub fn with_where_predicates_from_fields<F>(
item: &Item,
generics: &syn::Generics,
from_field: F,
) -> syn::Generics
where F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
{
aster::from_generics(generics.clone())
.with_predicates(
item.body.all_fields()
.flat_map(|field| from_field(&field.attrs))
.flat_map(|predicates| predicates.to_vec()))
.build()
}
// Puts the given bound on any generic type parameters that are used in fields
// for which filter returns true.
//
// For example, the following struct needs the bound `A: Serialize, B: Serialize`.
//
// struct S<'b, A, B: 'b, C> {
// a: A,
// b: Option<&'b B>
// #[serde(skip_serializing)]
// c: C,
// }
pub fn with_bound<F>(
item: &Item,
generics: &syn::Generics,
filter: F,
bound: &syn::Path,
) -> syn::Generics
where F: Fn(&attr::Field) -> bool,
{
struct FindTyParams {
// Set of all generic type parameters on the current struct (A, B, C in
// the example). Initialized up front.
all_ty_params: HashSet<syn::Ident>,
// Set of generic type parameters used in fields for which filter
// returns true (A and B in the example). Filled in as the visitor sees
// them.
relevant_ty_params: HashSet<syn::Ident>,
}
impl visit::Visitor for FindTyParams {
fn visit_path(&mut self, path: &syn::Path) {
if let Some(seg) = path.segments.last() {
if seg.ident == "PhantomData" {
// Hardcoded exception, because PhantomData<T> implements
// Serialize and Deserialize whether or not T implements it.
return;
}
}
if !path.global && path.segments.len() == 1 {
let id = path.segments[0].ident.clone();
if self.all_ty_params.contains(&id) {
self.relevant_ty_params.insert(id);
}
}
visit::walk_path(self, path);
}
}
let all_ty_params: HashSet<_> = generics.ty_params.iter()
.map(|ty_param| ty_param.ident.clone())
.collect();
let relevant_tys = item.body.all_fields()
.filter(|&field| filter(&field.attrs))
.map(|field| &field.ty);
let mut visitor = FindTyParams {
all_ty_params: all_ty_params,
relevant_ty_params: HashSet::new(),
};
for ty in relevant_tys {
visit::walk_ty(&mut visitor, ty);
}
aster::from_generics(generics.clone())
.with_predicates(
generics.ty_params.iter()
.map(|ty_param| ty_param.ident.clone())
.filter(|id| visitor.relevant_ty_params.contains(id))
.map(|id| aster::where_predicate()
// the type parameter that is being bounded e.g. T
.bound().build(aster::ty().id(id))
// the bound e.g. Serialize
.bound().trait_(bound.clone()).build()
.build()))
.build()
}
File diff suppressed because it is too large Load Diff
-172
View File
@@ -1,172 +0,0 @@
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "clippy", allow(used_underscore_binding))]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "192"]
extern crate serde_codegen_internals as internals;
#[cfg(feature = "with-syntex")]
extern crate syntex;
#[cfg(feature = "with-syntex")]
#[macro_use]
extern crate syntex_syntax as syntax;
extern crate syn;
#[macro_use]
extern crate quote;
#[cfg(feature = "with-syntex")]
use std::path::Path;
mod bound;
mod de;
mod ser;
#[cfg(feature = "with-syntex")]
fn syntex_registry() -> syntex::Registry {
use syntax::{ast, fold};
/// Strip the serde attributes from the crate.
#[cfg(feature = "with-syntex")]
fn strip_attributes(krate: ast::Crate) -> ast::Crate {
/// Helper folder that strips the serde attributes after the extensions have been expanded.
struct StripAttributeFolder;
impl fold::Folder for StripAttributeFolder {
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
if attr.value.name == "serde" {
if let ast::MetaItemKind::List(..) = attr.value.node {
return None;
}
}
Some(attr)
}
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
fold::noop_fold_mac(mac, self)
}
}
fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
}
let mut reg = syntex::Registry::new();
reg.add_attr("feature(custom_derive)");
reg.add_attr("feature(custom_attribute)");
reg.add_decorator("derive_Serialize", shim::expand_derive_serialize);
reg.add_decorator("derive_Deserialize", shim::expand_derive_deserialize);
reg.add_post_expansion_pass(strip_attributes);
reg
}
#[cfg(feature = "with-syntex")]
pub fn expand_str(src: &str) -> Result<String, syntex::Error> {
let src = src.to_owned();
let expand_thread = move || {
syntex_registry().expand_str("", "", &src)
};
syntex::with_extra_stack(expand_thread)
}
#[cfg(feature = "with-syntex")]
pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error>
where S: AsRef<Path>,
D: AsRef<Path>,
{
let src = src.as_ref().to_owned();
let dst = dst.as_ref().to_owned();
let expand_thread = move || {
syntex_registry().expand("", src, dst)
};
syntex::with_extra_stack(expand_thread)
}
macro_rules! shim {
($name:ident $pkg:ident :: $func:ident) => {
pub fn $func(
cx: &mut ::syntax::ext::base::ExtCtxt,
span: ::syntax::codemap::Span,
meta_item: &::syntax::ast::MetaItem,
annotatable: &::syntax::ext::base::Annotatable,
push: &mut FnMut(::syntax::ext::base::Annotatable)
) {
let item = match *annotatable {
::syntax::ext::base::Annotatable::Item(ref item) => item,
_ => {
cx.span_err(
meta_item.span,
concat!("`#[derive(",
stringify!($name),
")]` may only be applied to structs and enums"));
return;
}
};
use syntax::{attr, ast, visit};
struct MarkSerdeAttributesUsed;
impl<'a> visit::Visitor<'a> for MarkSerdeAttributesUsed {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
if attr.value.name == "serde" {
if let ast::MetaItemKind::List(..) = attr.value.node {
attr::mark_used(attr);
}
}
}
}
visit::walk_item(&mut MarkSerdeAttributesUsed, item);
use syntax::print::pprust;
let s = pprust::item_to_string(item);
use {syn, $pkg};
let syn_item = syn::parse_macro_input(&s).unwrap();
let expanded = match $pkg::$func(&syn_item) {
Ok(expanded) => expanded.to_string(),
Err(msg) => {
cx.span_err(span, &msg);
return;
}
};
use syntax::parse;
let name = stringify!($name).to_string();
let sess = cx.parse_sess;
let impl_item = parse::parse_item_from_source_str(name, expanded, sess);
push(::syntax::ext::base::Annotatable::Item(impl_item.unwrap().unwrap()));
}
};
}
#[cfg(feature = "with-syntex")]
mod shim {
shim!(Serialize ser::expand_derive_serialize);
shim!(Deserialize de::expand_derive_deserialize);
}
#[cfg(feature = "with-syn")]
#[doc(hidden)]
/// Not public API. Use the serde_derive crate.
pub fn expand_derive_serialize(item: &str) -> Result<quote::Tokens, String> {
let syn_item = syn::parse_macro_input(item).unwrap();
ser::expand_derive_serialize(&syn_item)
}
#[cfg(feature = "with-syn")]
#[doc(hidden)]
/// Not public API. Use the serde_derive crate.
pub fn expand_derive_deserialize(item: &str) -> Result<quote::Tokens, String> {
let syn_item = syn::parse_macro_input(item).unwrap();
de::expand_derive_deserialize(&syn_item)
}
-570
View File
@@ -1,570 +0,0 @@
use syn::{self, aster};
use quote::Tokens;
use bound;
use internals::ast::{Body, Field, Item, Style, Variant};
use internals::{self, attr};
pub fn expand_derive_serialize(item: &syn::MacroInput) -> Result<Tokens, String> {
let ctxt = internals::Ctxt::new();
let item = Item::from_ast(&ctxt, item);
try!(ctxt.check());
let impl_generics = build_impl_generics(&item);
let ty = aster::ty().path()
.segment(item.ident.clone()).with_generics(impl_generics.clone()).build()
.build();
let body = serialize_body(&item,
&impl_generics,
ty.clone());
let where_clause = &impl_generics.where_clause;
let dummy_const = aster::id(format!("_IMPL_SERIALIZE_FOR_{}", item.ident));
Ok(quote! {
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = {
extern crate serde as _serde;
#[automatically_derived]
impl #impl_generics _serde::ser::Serialize for #ty #where_clause {
fn serialize<__S>(&self, _serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
where __S: _serde::ser::Serializer
{
#body
}
}
};
})
}
// All the generics in the input, plus a bound `T: Serialize` for each generic
// field type that will be serialized by us.
fn build_impl_generics(item: &Item) -> syn::Generics {
let generics = bound::without_defaults(item.generics);
let generics = bound::with_where_predicates_from_fields(
item, &generics,
|attrs| attrs.ser_bound());
match item.attrs.ser_bound() {
Some(predicates) => {
bound::with_where_predicates(&generics, predicates)
}
None => {
bound::with_bound(item, &generics,
needs_serialize_bound,
&aster::path().ids(&["_serde", "ser", "Serialize"]).build())
}
}
}
// Fields with a `skip_serializing` or `serialize_with` attribute are not
// serialized by us so we do not generate a bound. Fields with a `bound`
// attribute specify their own bound so we do not generate one. All other fields
// may need a `T: Serialize` bound where T is the type of the field.
fn needs_serialize_bound(attrs: &attr::Field) -> bool {
!attrs.skip_serializing()
&& attrs.serialize_with().is_none()
&& attrs.ser_bound().is_none()
}
fn serialize_body(
item: &Item,
impl_generics: &syn::Generics,
ty: syn::Ty,
) -> Tokens {
match item.body {
Body::Enum(ref variants) => {
serialize_item_enum(
&item.ident,
impl_generics,
ty,
variants,
&item.attrs)
}
Body::Struct(Style::Struct, ref fields) => {
if fields.iter().any(|field| field.ident.is_none()) {
panic!("struct has unnamed fields");
}
serialize_struct(
impl_generics,
ty,
fields,
&item.attrs)
}
Body::Struct(Style::Tuple, ref fields) => {
if fields.iter().any(|field| field.ident.is_some()) {
panic!("tuple struct has named fields");
}
serialize_tuple_struct(
impl_generics,
ty,
fields,
&item.attrs)
}
Body::Struct(Style::Newtype, ref fields) => {
serialize_newtype_struct(
impl_generics,
ty,
&fields[0],
&item.attrs)
}
Body::Struct(Style::Unit, _) => {
serialize_unit_struct(
&item.attrs)
}
}
}
fn serialize_unit_struct(item_attrs: &attr::Item) -> Tokens {
let type_name = item_attrs.name().serialize_name();
quote! {
_serializer.serialize_unit_struct(#type_name)
}
}
fn serialize_newtype_struct(
impl_generics: &syn::Generics,
item_ty: syn::Ty,
field: &Field,
item_attrs: &attr::Item,
) -> Tokens {
let type_name = item_attrs.name().serialize_name();
let mut field_expr = quote!(&self.0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(
&item_ty, impl_generics, field.ty, path, field_expr);
}
quote! {
_serializer.serialize_newtype_struct(#type_name, #field_expr)
}
}
fn serialize_tuple_struct(
impl_generics: &syn::Generics,
ty: syn::Ty,
fields: &[Field],
item_attrs: &attr::Item,
) -> Tokens {
let serialize_stmts = serialize_tuple_struct_visitor(
ty.clone(),
fields,
impl_generics,
false,
aster::id("serialize_tuple_struct_elt"),
);
let type_name = item_attrs.name().serialize_name();
let len = serialize_stmts.len();
let let_mut = mut_if(len > 0);
quote! {
let #let_mut __serde_state = try!(_serializer.serialize_tuple_struct(#type_name, #len));
#(#serialize_stmts)*
_serializer.serialize_tuple_struct_end(__serde_state)
}
}
fn serialize_struct(
impl_generics: &syn::Generics,
ty: syn::Ty,
fields: &[Field],
item_attrs: &attr::Item,
) -> Tokens {
let serialize_fields = serialize_struct_visitor(
ty.clone(),
fields,
impl_generics,
false,
aster::id("serialize_struct_elt"),
);
let type_name = item_attrs.name().serialize_name();
let mut serialized_fields = fields.iter()
.filter(|&field| !field.attrs.skip_serializing())
.peekable();
let let_mut = mut_if(serialized_fields.peek().is_some());
let len = serialized_fields
.map(|field| {
let ident = field.ident.clone().expect("struct has unnamed fields");
let field_expr = quote!(&self.#ident);
match field.attrs.skip_serializing_if() {
Some(path) => quote!(if #path(#field_expr) { 0 } else { 1 }),
None => quote!(1),
}
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
quote! {
let #let_mut __serde_state = try!(_serializer.serialize_struct(#type_name, #len));
#(#serialize_fields)*
_serializer.serialize_struct_end(__serde_state)
}
}
fn serialize_item_enum(
type_ident: &syn::Ident,
impl_generics: &syn::Generics,
ty: syn::Ty,
variants: &[Variant],
item_attrs: &attr::Item,
) -> Tokens {
let arms: Vec<_> =
variants.iter()
.enumerate()
.map(|(variant_index, variant)| {
serialize_variant(
type_ident,
impl_generics,
ty.clone(),
variant,
variant_index,
item_attrs,
)
})
.collect();
quote! {
match *self {
#(#arms)*
}
}
}
fn serialize_variant(
type_ident: &syn::Ident,
generics: &syn::Generics,
ty: syn::Ty,
variant: &Variant,
variant_index: usize,
item_attrs: &attr::Item,
) -> Tokens {
let type_name = item_attrs.name().serialize_name();
let variant_ident = variant.ident.clone();
let variant_name = variant.attrs.name().serialize_name();
if variant.attrs.skip_serializing() {
let skipped_msg = format!("The enum variant {}::{} cannot be serialized",
type_ident, variant_ident);
let skipped_err = quote! {
Err(_serde::ser::Error::invalid_value(#skipped_msg))
};
let fields_pat = match variant.style {
Style::Unit => quote!(),
Style::Newtype | Style::Tuple => quote!( (..) ),
Style::Struct => quote!( {..} ),
};
quote! {
#type_ident::#variant_ident #fields_pat => #skipped_err,
}
} else { // variant wasn't skipped
match variant.style {
Style::Unit => {
quote! {
#type_ident::#variant_ident =>
_serde::ser::Serializer::serialize_unit_variant(
_serializer,
#type_name,
#variant_index,
#variant_name,
),
}
},
Style::Newtype => {
let block = serialize_newtype_variant(
type_name,
variant_index,
variant_name,
ty,
generics,
&variant.fields[0],
);
quote! {
#type_ident::#variant_ident(ref __simple_value) => #block,
}
},
Style::Tuple => {
let field_names = (0 .. variant.fields.len())
.map(|i| aster::id(format!("__field{}", i)));
let block = serialize_tuple_variant(
type_name,
variant_index,
variant_name,
generics,
ty,
&variant.fields,
);
quote! {
#type_ident::#variant_ident(#(ref #field_names),*) => { #block }
}
}
Style::Struct => {
let fields = variant.fields.iter()
.map(|f| f.ident.clone().expect("struct variant has unnamed fields"));
let block = serialize_struct_variant(
variant_index,
variant_name,
generics,
ty,
&variant.fields,
item_attrs,
);
quote! {
#type_ident::#variant_ident { #(ref #fields),* } => { #block }
}
}
}
}
}
fn serialize_newtype_variant(
type_name: String,
variant_index: usize,
variant_name: String,
item_ty: syn::Ty,
generics: &syn::Generics,
field: &Field,
) -> Tokens {
let mut field_expr = quote!(__simple_value);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(
&item_ty, generics, field.ty, path, field_expr);
}
quote! {
_serde::ser::Serializer::serialize_newtype_variant(
_serializer,
#type_name,
#variant_index,
#variant_name,
#field_expr,
)
}
}
fn serialize_tuple_variant(
type_name: String,
variant_index: usize,
variant_name: String,
generics: &syn::Generics,
structure_ty: syn::Ty,
fields: &[Field],
) -> Tokens {
let serialize_stmts = serialize_tuple_struct_visitor(
structure_ty,
fields,
generics,
true,
aster::id("serialize_tuple_variant_elt"),
);
let len = serialize_stmts.len();
let let_mut = mut_if(len > 0);
quote! {
let #let_mut __serde_state = try!(_serializer.serialize_tuple_variant(
#type_name,
#variant_index,
#variant_name,
#len));
#(#serialize_stmts)*
_serializer.serialize_tuple_variant_end(__serde_state)
}
}
fn serialize_struct_variant(
variant_index: usize,
variant_name: String,
generics: &syn::Generics,
ty: syn::Ty,
fields: &[Field],
item_attrs: &attr::Item,
) -> Tokens {
let serialize_fields = serialize_struct_visitor(
ty.clone(),
fields,
generics,
true,
aster::id("serialize_struct_variant_elt"),
);
let item_name = item_attrs.name().serialize_name();
let mut serialized_fields = fields.iter()
.filter(|&field| !field.attrs.skip_serializing())
.peekable();
let let_mut = mut_if(serialized_fields.peek().is_some());
let len = serialized_fields
.map(|field| {
let ident = field.ident.clone().expect("struct has unnamed fields");
match field.attrs.skip_serializing_if() {
Some(path) => quote!(if #path(#ident) { 0 } else { 1 }),
None => quote!(1),
}
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
quote! {
let #let_mut __serde_state = try!(_serializer.serialize_struct_variant(
#item_name,
#variant_index,
#variant_name,
#len,
));
#(#serialize_fields)*
_serializer.serialize_struct_variant_end(__serde_state)
}
}
fn serialize_tuple_struct_visitor(
structure_ty: syn::Ty,
fields: &[Field],
generics: &syn::Generics,
is_enum: bool,
func: syn::Ident,
) -> Vec<Tokens> {
fields.iter()
.enumerate()
.map(|(i, field)| {
let mut field_expr = if is_enum {
let id = aster::id(format!("__field{}", i));
quote!(#id)
} else {
let i = aster::id(i);
quote!(&self.#i)
};
let skip = field.attrs.skip_serializing_if()
.map(|path| quote!(#path(#field_expr)));
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(
&structure_ty, generics, field.ty, path, field_expr);
}
let ser = quote! {
try!(_serializer.#func(&mut __serde_state, #field_expr));
};
match skip {
None => ser,
Some(skip) => quote!(if !#skip { #ser }),
}
})
.collect()
}
fn serialize_struct_visitor(
structure_ty: syn::Ty,
fields: &[Field],
generics: &syn::Generics,
is_enum: bool,
func: syn::Ident,
) -> Vec<Tokens> {
fields.iter()
.filter(|&field| !field.attrs.skip_serializing())
.map(|field| {
let ident = field.ident.clone().expect("struct has unnamed field");
let mut field_expr = if is_enum {
quote!(#ident)
} else {
quote!(&self.#ident)
};
let key_expr = field.attrs.name().serialize_name();
let skip = field.attrs.skip_serializing_if()
.map(|path| quote!(#path(#field_expr)));
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(
&structure_ty, generics, field.ty, path, field_expr)
}
let ser = quote! {
try!(_serializer.#func(&mut __serde_state, #key_expr, #field_expr));
};
match skip {
None => ser,
Some(skip) => quote!(if !#skip { #ser }),
}
})
.collect()
}
fn wrap_serialize_with(
item_ty: &syn::Ty,
generics: &syn::Generics,
field_ty: &syn::Ty,
path: &syn::Path,
value: Tokens,
) -> Tokens {
let where_clause = &generics.where_clause;
let wrapper_generics = aster::from_generics(generics.clone())
.add_lifetime_bound("'__a")
.lifetime_name("'__a")
.build();
let wrapper_ty = aster::path()
.segment("__SerializeWith")
.with_generics(wrapper_generics.clone())
.build()
.build();
quote!({
struct __SerializeWith #wrapper_generics #where_clause {
value: &'__a #field_ty,
phantom: ::std::marker::PhantomData<#item_ty>,
}
impl #wrapper_generics _serde::ser::Serialize for #wrapper_ty #where_clause {
fn serialize<__S>(&self, __s: &mut __S) -> ::std::result::Result<(), __S::Error>
where __S: _serde::ser::Serializer
{
#path(self.value, __s)
}
}
__SerializeWith {
value: #value,
phantom: ::std::marker::PhantomData::<#item_ty>,
}
})
}
// Serialization of an empty struct results in code like:
//
// let mut __serde_state = try!(serializer.serialize_struct("S", 0));
// serializer.serialize_struct_end(__serde_state)
//
// where we want to omit the `mut` to avoid a warning.
fn mut_if(is_mut: bool) -> Option<Tokens> {
if is_mut {
Some(quote!(mut))
} else {
None
}
}
+7 -7
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_codegen_internals"
version = "0.11.3"
version = "0.14.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "AST representation used by Serde codegen. Unstable."
@@ -8,11 +8,11 @@ homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://docs.serde.rs/serde_codegen_internals/"
keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
[features]
unstable-testing = ["clippy"]
readme = "../README.md"
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
[dependencies]
clippy = { version = "^0.*", optional = true }
syn = "0.10"
syn = { version = "0.11", default-features = false, features = ["parsing"] }
[badges]
travis-ci = { repository = "serde-rs/serde" }
+1
View File
@@ -0,0 +1 @@
../LICENSE-APACHE
+1
View File
@@ -0,0 +1 @@
../LICENSE-MIT
+1
View File
@@ -0,0 +1 @@
../README.md
+7 -17
View File
@@ -39,9 +39,7 @@ impl<'a> Item<'a> {
let attrs = attr::Item::from_ast(cx, item);
let body = match item.body {
syn::Body::Enum(ref variants) => {
Body::Enum(enum_from_ast(cx, variants))
}
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
syn::Body::Struct(ref variant_data) => {
let (style, fields) = struct_from_ast(cx, variant_data);
Body::Struct(style, fields)
@@ -58,15 +56,13 @@ impl<'a> Item<'a> {
}
impl<'a> Body<'a> {
pub fn all_fields(&'a self) -> Box<Iterator<Item=&'a Field<'a>> + 'a> {
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
match *self {
Body::Enum(ref variants) => {
Box::new(variants.iter()
.flat_map(|variant| variant.fields.iter()))
}
Body::Struct(_, ref fields) => {
Box::new(fields.iter())
.flat_map(|variant| variant.fields.iter()))
}
Body::Struct(_, ref fields) => Box::new(fields.iter()),
}
}
}
@@ -87,18 +83,12 @@ fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>
fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData) -> (Style, Vec<Field<'a>>) {
match *data {
syn::VariantData::Struct(ref fields) => {
(Style::Struct, fields_from_ast(cx, fields))
}
syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields)),
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
(Style::Newtype, fields_from_ast(cx, fields))
}
syn::VariantData::Tuple(ref fields) => {
(Style::Tuple, fields_from_ast(cx, fields))
}
syn::VariantData::Unit => {
(Style::Unit, Vec::new())
}
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields)),
syn::VariantData::Unit => (Style::Unit, Vec::new()),
}
}
+215 -43
View File
@@ -90,8 +90,42 @@ impl Name {
pub struct Item {
name: Name,
deny_unknown_fields: bool,
default: Default,
ser_bound: Option<Vec<syn::WherePredicate>>,
de_bound: Option<Vec<syn::WherePredicate>>,
tag: EnumTag,
}
/// Styles of representing an enum.
#[derive(Debug)]
pub enum EnumTag {
/// The default.
///
/// ```json
/// {"variant1": {"key1": "value1", "key2": "value2"}}
/// ```
External,
/// `#[serde(tag = "type")]`
///
/// ```json
/// {"type": "variant1", "key1": "value1", "key2": "value2"}
/// ```
Internal { tag: String },
/// `#[serde(tag = "t", content = "c")]`
///
/// ```json
/// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}}
/// ```
Adjacent { tag: String, content: String },
/// `#[serde(untagged)]`
///
/// ```json
/// {"key1": "value1", "key2": "value2"}
/// ```
None,
}
impl Item {
@@ -100,8 +134,12 @@ impl Item {
let mut ser_name = Attr::none(cx, "rename");
let mut de_name = Attr::none(cx, "rename");
let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields");
let mut default = Attr::none(cx, "default");
let mut ser_bound = Attr::none(cx, "bound");
let mut de_bound = Attr::none(cx, "bound");
let mut untagged = BoolAttr::none(cx, "untagged");
let mut internal_tag = Attr::none(cx, "tag");
let mut content = Attr::none(cx, "content");
for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) {
for meta_item in meta_items {
@@ -127,9 +165,38 @@ impl Item {
deny_unknown_fields.set_true();
}
// Parse `#[serde(default)]`
MetaItem(Word(ref name)) if name == "default" => {
match item.body {
syn::Body::Struct(syn::VariantData::Struct(_)) => {
default.set(Default::Default);
}
_ => {
cx.error("#[serde(default)] can only be used on structs \
with named fields")
}
}
}
// Parse `#[serde(default="...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
match item.body {
syn::Body::Struct(syn::VariantData::Struct(_)) => {
default.set(Default::Path(path));
}
_ => {
cx.error("#[serde(default = \"...\")] can only be used \
on structs with named fields")
}
}
}
}
// Parse `#[serde(bound="D: Serialize")]`
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => {
if let Ok(where_predicates) = parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
if let Ok(where_predicates) =
parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates);
}
@@ -143,26 +210,111 @@ impl Item {
}
}
// Parse `#[serde(untagged)]`
MetaItem(Word(ref name)) if name == "untagged" => {
match item.body {
syn::Body::Enum(_) => {
untagged.set_true();
}
syn::Body::Struct(_) => {
cx.error("#[serde(untagged)] can only be used on enums")
}
}
}
// Parse `#[serde(tag = "type")]`
MetaItem(NameValue(ref name, ref lit)) if name == "tag" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
match item.body {
syn::Body::Enum(_) => {
internal_tag.set(s);
}
syn::Body::Struct(_) => {
cx.error("#[serde(tag = \"...\")] can only be used on enums")
}
}
}
}
// Parse `#[serde(content = "c")]`
MetaItem(NameValue(ref name, ref lit)) if name == "content" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
match item.body {
syn::Body::Enum(_) => {
content.set(s);
}
syn::Body::Struct(_) => {
cx.error("#[serde(content = \"...\")] can only be used on enums")
}
}
}
}
MetaItem(ref meta_item) => {
cx.error(format!("unknown serde container attribute `{}`",
meta_item.name()));
}
Literal(_) => {
cx.error(format!("unexpected literal in serde container attribute"));
cx.error("unexpected literal in serde container attribute");
}
}
}
}
let tag = match (untagged.get(), internal_tag.get(), content.get()) {
(false, None, None) => EnumTag::External,
(true, None, None) => EnumTag::None,
(false, Some(tag), None) => {
// Check that there are no tuple variants.
if let syn::Body::Enum(ref variants) = item.body {
for variant in variants {
match variant.data {
syn::VariantData::Struct(_) |
syn::VariantData::Unit => {}
syn::VariantData::Tuple(ref fields) => {
if fields.len() != 1 {
cx.error("#[serde(tag = \"...\")] cannot be used with tuple \
variants");
break;
}
}
}
}
}
EnumTag::Internal { tag: tag }
}
(true, Some(_), None) => {
cx.error("enum cannot be both untagged and internally tagged");
EnumTag::External // doesn't matter, will error
}
(false, None, Some(_)) => {
cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together");
EnumTag::External
}
(true, None, Some(_)) => {
cx.error("untagged enum cannot have #[serde(content = \"...\")]");
EnumTag::External
}
(false, Some(tag), Some(content)) => {
EnumTag::Adjacent { tag: tag, content: content }
}
(true, Some(_), Some(_)) => {
cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]");
EnumTag::External
}
};
Item {
name: Name {
serialize: ser_name.get().unwrap_or_else(|| item.ident.to_string()),
deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()),
},
deny_unknown_fields: deny_unknown_fields.get(),
default: default.get().unwrap_or(Default::None),
ser_bound: ser_bound.get(),
de_bound: de_bound.get(),
tag: tag,
}
}
@@ -174,6 +326,10 @@ impl Item {
self.deny_unknown_fields
}
pub fn default(&self) -> &Default {
&self.default
}
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
self.ser_bound.as_ref().map(|vec| &vec[..])
}
@@ -181,6 +337,10 @@ impl Item {
pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> {
self.de_bound.as_ref().map(|vec| &vec[..])
}
pub fn tag(&self) -> &EnumTag {
&self.tag
}
}
/// Represents variant attribute information
@@ -226,12 +386,11 @@ impl Variant {
}
MetaItem(ref meta_item) => {
cx.error(format!("unknown serde variant attribute `{}`",
meta_item.name()));
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
}
Literal(_) => {
cx.error(format!("unexpected literal in serde variant attribute"));
cx.error("unexpected literal in serde variant attribute");
}
}
}
@@ -267,7 +426,7 @@ pub struct Field {
skip_serializing: bool,
skip_deserializing: bool,
skip_serializing_if: Option<syn::Path>,
default: FieldDefault,
default: Default,
serialize_with: Option<syn::Path>,
deserialize_with: Option<syn::Path>,
ser_bound: Option<Vec<syn::WherePredicate>>,
@@ -276,7 +435,7 @@ pub struct Field {
/// Represents the default to use for a field when deserializing.
#[derive(Debug, PartialEq)]
pub enum FieldDefault {
pub enum Default {
/// Field must always be specified because it does not have a default.
None,
/// The default is given by `std::default::Default::default()`.
@@ -287,9 +446,7 @@ pub enum FieldDefault {
impl Field {
/// Extract out the `#[serde(...)]` attributes from a struct field.
pub fn from_ast(cx: &Ctxt,
index: usize,
field: &syn::Field) -> Self {
pub fn from_ast(cx: &Ctxt, index: usize, field: &syn::Field) -> Self {
let mut ser_name = Attr::none(cx, "rename");
let mut de_name = Attr::none(cx, "rename");
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
@@ -327,13 +484,13 @@ impl Field {
// Parse `#[serde(default)]`
MetaItem(Word(ref name)) if name == "default" => {
default.set(FieldDefault::Default);
default.set(Default::Default);
}
// Parse `#[serde(default="...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
default.set(FieldDefault::Path(path));
default.set(Default::Path(path));
}
}
@@ -368,9 +525,22 @@ impl Field {
}
}
// Parse `#[serde(with="...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
let mut ser_path = path.clone();
ser_path.segments.push("serialize".into());
serialize_with.set(ser_path);
let mut de_path = path;
de_path.segments.push("deserialize".into());
deserialize_with.set(de_path);
}
}
// Parse `#[serde(bound="D: Serialize")]`
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => {
if let Ok(where_predicates) = parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
if let Ok(where_predicates) =
parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates);
}
@@ -385,12 +555,11 @@ impl Field {
}
MetaItem(ref meta_item) => {
cx.error(format!("unknown serde field attribute `{}`",
meta_item.name()));
cx.error(format!("unknown serde field attribute `{}`", meta_item.name()));
}
Literal(_) => {
cx.error(format!("unexpected literal in serde field attribute"));
cx.error("unexpected literal in serde field attribute");
}
}
}
@@ -399,18 +568,18 @@ impl Field {
// Is skip_deserializing, initialize the field to Default::default()
// unless a different default is specified by `#[serde(default="...")]`
if skip_deserializing.0.value.is_some() {
default.set_if_none(FieldDefault::Default);
default.set_if_none(Default::Default);
}
Field {
name: Name {
serialize: ser_name.get().unwrap_or(ident.clone()),
serialize: ser_name.get().unwrap_or_else(|| ident.clone()),
deserialize: de_name.get().unwrap_or(ident),
},
skip_serializing: skip_serializing.get(),
skip_deserializing: skip_deserializing.get(),
skip_serializing_if: skip_serializing_if.get(),
default: default.get().unwrap_or(FieldDefault::None),
default: default.get().unwrap_or(Default::None),
serialize_with: serialize_with.get(),
deserialize_with: deserialize_with.get(),
ser_bound: ser_bound.get(),
@@ -434,7 +603,7 @@ impl Field {
self.skip_serializing_if.as_ref()
}
pub fn default(&self) -> &FieldDefault {
pub fn default(&self) -> &Default {
&self.default
}
@@ -457,13 +626,12 @@ impl Field {
type SerAndDe<T> = (Option<T>, Option<T>);
fn get_ser_and_de<T, F>(
cx: &Ctxt,
attr_name: &'static str,
items: &[syn::NestedMetaItem],
f: F
) -> Result<SerAndDe<T>, ()>
where F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result<T, ()>,
fn get_ser_and_de<T, F>(cx: &Ctxt,
attr_name: &'static str,
items: &[syn::NestedMetaItem],
f: F)
-> Result<SerAndDe<T>, ()>
where F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result<T, ()>
{
let mut ser_item = Attr::none(cx, attr_name);
let mut de_item = Attr::none(cx, attr_name);
@@ -483,7 +651,8 @@ fn get_ser_and_de<T, F>(
}
_ => {
cx.error(format!("malformed {0} attribute, expected `{0}(serialize = ..., deserialize = ...)`",
cx.error(format!("malformed {0} attribute, expected `{0}(serialize = ..., \
deserialize = ...)`",
attr_name));
return Err(());
}
@@ -493,35 +662,34 @@ fn get_ser_and_de<T, F>(
Ok((ser_item.get(), de_item.get()))
}
fn get_renames(
cx: &Ctxt,
items: &[syn::NestedMetaItem],
) -> Result<SerAndDe<String>, ()> {
fn get_renames(cx: &Ctxt, items: &[syn::NestedMetaItem]) -> Result<SerAndDe<String>, ()> {
get_ser_and_de(cx, "rename", items, get_string_from_lit)
}
fn get_where_predicates(
cx: &Ctxt,
items: &[syn::NestedMetaItem],
) -> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> {
fn get_where_predicates(cx: &Ctxt,
items: &[syn::NestedMetaItem])
-> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> {
get_ser_and_de(cx, "bound", items, parse_lit_into_where)
}
pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMetaItem>> {
match attr.value {
List(ref name, ref items) if name == "serde" => {
Some(items.iter().cloned().collect())
}
_ => None
List(ref name, ref items) if name == "serde" => Some(items.iter().cloned().collect()),
_ => None,
}
}
fn get_string_from_lit(cx: &Ctxt, attr_name: &str, meta_item_name: &str, lit: &syn::Lit) -> Result<String, ()> {
fn get_string_from_lit(cx: &Ctxt,
attr_name: &str,
meta_item_name: &str,
lit: &syn::Lit)
-> Result<String, ()> {
if let syn::Lit::Str(ref s, _) = *lit {
Ok(s.clone())
} else {
cx.error(format!("expected serde {} attribute to be a string: `{} = \"...\"`",
attr_name, meta_item_name));
attr_name,
meta_item_name));
Err(())
}
}
@@ -531,7 +699,11 @@ fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn
syn::parse_path(&string).map_err(|err| cx.error(err))
}
fn parse_lit_into_where(cx: &Ctxt, attr_name: &str, meta_item_name: &str, lit: &syn::Lit) -> Result<Vec<syn::WherePredicate>, ()> {
fn parse_lit_into_where(cx: &Ctxt,
attr_name: &str,
meta_item_name: &str,
lit: &syn::Lit)
-> Result<Vec<syn::WherePredicate>, ()> {
let string = try!(get_string_from_lit(cx, attr_name, meta_item_name, lit));
if string.is_empty() {
return Ok(Vec::new());
+1 -3
View File
@@ -8,9 +8,7 @@ pub struct Ctxt {
impl Ctxt {
pub fn new() -> Self {
Ctxt {
errors: RefCell::new(Some(Vec::new())),
}
Ctxt { errors: RefCell::new(Some(Vec::new())) }
}
pub fn error<T: Display>(&self, msg: T) {
-3
View File
@@ -1,6 +1,3 @@
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", feature(plugin))]
extern crate syn;
pub mod ast;
+14 -14
View File
@@ -1,27 +1,27 @@
[package]
name = "serde_derive"
version = "0.8.22"
version = "0.9.8"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://serde.rs/codegen.html"
keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
keywords = ["serde", "serialization", "no_std"]
readme = "../README.md"
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
[features]
unstable = []
[badges]
travis-ci = { repository = "serde-rs/serde" }
[lib]
name = "serde_derive"
proc-macro = true
[dependencies.serde_codegen]
version = "=0.8.22"
path = "../serde_codegen"
default-features = false
features = ["with-syn"]
[dev-dependencies]
compiletest_rs = "^0.2.0"
fnv = "1.0"
serde = { version = "0.8.22", path = "../serde" }
serde_test = { version = "0.8.22", path = "../serde_test" }
[dependencies]
quote = "0.3.8"
serde_codegen_internals = { version = "=0.14.0", default-features = false, path = "../serde_codegen_internals" }
syn = { version = "0.11", features = ["visit"] }
+1
View File
@@ -0,0 +1 @@
../LICENSE-APACHE
+1
View File
@@ -0,0 +1 @@
../LICENSE-MIT
+1
View File
@@ -0,0 +1 @@
../README.md
+228
View File
@@ -0,0 +1,228 @@
use std::collections::HashSet;
use syn::{self, visit};
use internals::ast::Item;
use internals::attr;
macro_rules! path {
($first:ident $(:: $rest:ident)*) => {
syn::Path {
global: false,
segments: vec![
stringify!($first).into(),
$(
stringify!($rest).into(),
)*
],
}
};
(::$first:ident $(:: $rest:ident)*) => {
syn::Path {
global: true,
segments: vec![
stringify!($first).into(),
$(
stringify!($rest).into(),
)*
],
}
};
}
// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
// allowed here".
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
syn::Generics {
ty_params: generics.ty_params
.iter()
.map(|ty_param| syn::TyParam { default: None, ..ty_param.clone() })
.collect(),
..generics.clone()
}
}
pub fn with_where_predicates(generics: &syn::Generics,
predicates: &[syn::WherePredicate])
-> syn::Generics {
let mut generics = generics.clone();
generics.where_clause.predicates.extend_from_slice(predicates);
generics
}
pub fn with_where_predicates_from_fields<F>(item: &Item,
generics: &syn::Generics,
from_field: F)
-> syn::Generics
where F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>
{
let predicates = item.body
.all_fields()
.flat_map(|field| from_field(&field.attrs))
.flat_map(|predicates| predicates.to_vec());
let mut generics = generics.clone();
generics.where_clause.predicates.extend(predicates);
generics
}
// Puts the given bound on any generic type parameters that are used in fields
// for which filter returns true.
//
// For example, the following struct needs the bound `A: Serialize, B: Serialize`.
//
// struct S<'b, A, B: 'b, C> {
// a: A,
// b: Option<&'b B>
// #[serde(skip_serializing)]
// c: C,
// }
pub fn with_bound<F>(item: &Item,
generics: &syn::Generics,
filter: F,
bound: &syn::Path)
-> syn::Generics
where F: Fn(&attr::Field) -> bool
{
struct FindTyParams {
// Set of all generic type parameters on the current struct (A, B, C in
// the example). Initialized up front.
all_ty_params: HashSet<syn::Ident>,
// Set of generic type parameters used in fields for which filter
// returns true (A and B in the example). Filled in as the visitor sees
// them.
relevant_ty_params: HashSet<syn::Ident>,
}
impl visit::Visitor for FindTyParams {
fn visit_path(&mut self, path: &syn::Path) {
if let Some(seg) = path.segments.last() {
if seg.ident == "PhantomData" {
// Hardcoded exception, because PhantomData<T> implements
// Serialize and Deserialize whether or not T implements it.
return;
}
}
if !path.global && path.segments.len() == 1 {
let id = path.segments[0].ident.clone();
if self.all_ty_params.contains(&id) {
self.relevant_ty_params.insert(id);
}
}
visit::walk_path(self, path);
}
}
let all_ty_params: HashSet<_> = generics.ty_params
.iter()
.map(|ty_param| ty_param.ident.clone())
.collect();
let relevant_tys = item.body
.all_fields()
.filter(|&field| filter(&field.attrs))
.map(|field| &field.ty);
let mut visitor = FindTyParams {
all_ty_params: all_ty_params,
relevant_ty_params: HashSet::new(),
};
for ty in relevant_tys {
visit::walk_ty(&mut visitor, ty);
}
let new_predicates = generics.ty_params
.iter()
.map(|ty_param| ty_param.ident.clone())
.filter(|id| visitor.relevant_ty_params.contains(id))
.map(|id| {
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
bound_lifetimes: Vec::new(),
// the type parameter that is being bounded e.g. T
bounded_ty: syn::Ty::Path(None, id.into()),
// the bound e.g. Serialize
bounds: vec![syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: Vec::new(),
trait_ref: bound.clone(),
},
syn::TraitBoundModifier::None
)],
})
});
let mut generics = generics.clone();
generics.where_clause.predicates.extend(new_predicates);
generics
}
pub fn with_self_bound(item: &Item,
generics: &syn::Generics,
bound: &syn::Path)
-> syn::Generics
{
let mut generics = generics.clone();
generics.where_clause.predicates.push(
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
bound_lifetimes: Vec::new(),
// the type that is being bounded e.g. MyStruct<'a, T>
bounded_ty: type_of_item(item),
// the bound e.g. Default
bounds: vec![syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: Vec::new(),
trait_ref: bound.clone(),
},
syn::TraitBoundModifier::None
)],
})
);
generics
}
pub fn with_lifetime_bound(generics: &syn::Generics,
lifetime: &str)
-> syn::Generics {
let mut generics = generics.clone();
for lifetime_def in &mut generics.lifetimes {
lifetime_def.bounds.push(syn::Lifetime::new(lifetime));
}
for ty_param in &mut generics.ty_params {
ty_param.bounds.push(syn::TyParamBound::Region(syn::Lifetime::new(lifetime)));
}
generics.lifetimes.push(syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new(lifetime),
bounds: Vec::new(),
});
generics
}
fn type_of_item(item: &Item) -> syn::Ty {
syn::Ty::Path(None, syn::Path {
global: false,
segments: vec![
syn::PathSegment {
ident: item.ident.clone(),
parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData {
lifetimes: item.generics
.lifetimes
.iter()
.map(|def| def.lifetime.clone())
.collect(),
types: item.generics
.ty_params
.iter()
.map(|param| syn::Ty::Path(None, param.ident.clone().into()))
.collect(),
bindings: Vec::new(),
}),
}
]
})
}
File diff suppressed because it is too large Load Diff
+67
View File
@@ -0,0 +1,67 @@
use quote::{Tokens, ToTokens};
pub enum Fragment {
/// Tokens that can be used as an expression.
Expr(Tokens),
/// Tokens that can be used inside a block. The surrounding curly braces are
/// not part of these tokens.
Block(Tokens),
}
macro_rules! quote_expr {
($($tt:tt)*) => {
$crate::fragment::Fragment::Expr(quote!($($tt)*))
}
}
macro_rules! quote_block {
($($tt:tt)*) => {
$crate::fragment::Fragment::Block(quote!($($tt)*))
}
}
/// Interpolate a fragment in place of an expression. This involves surrounding
/// Block fragments in curly braces.
pub struct Expr(pub Fragment);
impl ToTokens for Expr {
fn to_tokens(&self, out: &mut Tokens) {
match self.0 {
Fragment::Expr(ref expr) => expr.to_tokens(out),
Fragment::Block(ref block) => {
out.append("{");
block.to_tokens(out);
out.append("}");
}
}
}
}
/// Interpolate a fragment as the statements of a block.
pub struct Stmts(pub Fragment);
impl ToTokens for Stmts {
fn to_tokens(&self, out: &mut Tokens) {
match self.0 {
Fragment::Expr(ref expr) => expr.to_tokens(out),
Fragment::Block(ref block) => block.to_tokens(out),
}
}
}
/// Interpolate a fragment as the value part of a `match` expression. This
/// involves putting a comma after expressions and curly braces around blocks.
pub struct Match(pub Fragment);
impl ToTokens for Match {
fn to_tokens(&self, out: &mut Tokens) {
match self.0 {
Fragment::Expr(ref expr) => {
expr.to_tokens(out);
out.append(",");
}
Fragment::Block(ref block) => {
out.append("{");
block.to_tokens(out);
out.append("}");
}
}
}
}
+24 -4
View File
@@ -1,11 +1,30 @@
extern crate proc_macro;
extern crate serde_codegen;
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "192"]
extern crate syn;
#[macro_use]
extern crate quote;
extern crate serde_codegen_internals as internals;
extern crate proc_macro;
use proc_macro::TokenStream;
#[macro_use]
mod bound;
#[macro_use]
mod fragment;
mod ser;
mod de;
#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
match serde_codegen::expand_derive_serialize(&input.to_string()) {
let input = syn::parse_derive_input(&input.to_string()).unwrap();
match ser::expand_derive_serialize(&input) {
Ok(expanded) => expanded.parse().unwrap(),
Err(msg) => panic!(msg),
}
@@ -13,7 +32,8 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream {
#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
match serde_codegen::expand_derive_deserialize(&input.to_string()) {
let input = syn::parse_derive_input(&input.to_string()).unwrap();
match de::expand_derive_deserialize(&input) {
Ok(expanded) => expanded.parse().unwrap(),
Err(msg) => panic!(msg),
}
+782
View File
@@ -0,0 +1,782 @@
use syn::{self, Ident};
use quote::Tokens;
use bound;
use fragment::{Fragment, Stmts, Match};
use internals::ast::{Body, Field, Item, Style, Variant};
use internals::{self, attr};
pub fn expand_derive_serialize(item: &syn::DeriveInput) -> Result<Tokens, String> {
let ctxt = internals::Ctxt::new();
let item = Item::from_ast(&ctxt, item);
try!(ctxt.check());
let ident = &item.ident;
let generics = build_generics(&item);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let dummy_const = Ident::new(format!("_IMPL_SERIALIZE_FOR_{}", ident));
let body = Stmts(serialize_body(&item, &generics));
Ok(quote! {
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = {
extern crate serde as _serde;
#[automatically_derived]
impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause {
fn serialize<__S>(&self, _serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where __S: _serde::Serializer
{
#body
}
}
};
})
}
// All the generics in the input, plus a bound `T: Serialize` for each generic
// field type that will be serialized by us.
fn build_generics(item: &Item) -> syn::Generics {
let generics = bound::without_defaults(item.generics);
let generics =
bound::with_where_predicates_from_fields(item, &generics, attr::Field::ser_bound);
match item.attrs.ser_bound() {
Some(predicates) => bound::with_where_predicates(&generics, predicates),
None => {
bound::with_bound(item,
&generics,
needs_serialize_bound,
&path!(_serde::Serialize))
}
}
}
// Fields with a `skip_serializing` or `serialize_with` attribute are not
// serialized by us so we do not generate a bound. Fields with a `bound`
// attribute specify their own bound so we do not generate one. All other fields
// may need a `T: Serialize` bound where T is the type of the field.
fn needs_serialize_bound(attrs: &attr::Field) -> bool {
!attrs.skip_serializing() && attrs.serialize_with().is_none() && attrs.ser_bound().is_none()
}
fn serialize_body(item: &Item, generics: &syn::Generics) -> Fragment {
match item.body {
Body::Enum(ref variants) => {
serialize_item_enum(&item.ident, generics, variants, &item.attrs)
}
Body::Struct(Style::Struct, ref fields) => {
if fields.iter().any(|field| field.ident.is_none()) {
panic!("struct has unnamed fields");
}
serialize_struct(&item.ident, generics, fields, &item.attrs)
}
Body::Struct(Style::Tuple, ref fields) => {
if fields.iter().any(|field| field.ident.is_some()) {
panic!("tuple struct has named fields");
}
serialize_tuple_struct(&item.ident, generics, fields, &item.attrs)
}
Body::Struct(Style::Newtype, ref fields) => {
serialize_newtype_struct(&item.ident, generics, &fields[0], &item.attrs)
}
Body::Struct(Style::Unit, _) => serialize_unit_struct(&item.attrs),
}
}
fn serialize_unit_struct(item_attrs: &attr::Item) -> Fragment {
let type_name = item_attrs.name().serialize_name();
quote_expr! {
_serde::Serializer::serialize_unit_struct(_serializer, #type_name)
}
}
fn serialize_newtype_struct(ident: &syn::Ident,
generics: &syn::Generics,
field: &Field,
item_attrs: &attr::Item)
-> Fragment {
let type_name = item_attrs.name().serialize_name();
let mut field_expr = quote!(&self.0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(ident, generics, field.ty, path, field_expr);
}
quote_expr! {
_serde::Serializer::serialize_newtype_struct(_serializer, #type_name, #field_expr)
}
}
fn serialize_tuple_struct(ident: &syn::Ident,
generics: &syn::Generics,
fields: &[Field],
item_attrs: &attr::Item)
-> Fragment {
let serialize_stmts =
serialize_tuple_struct_visitor(ident,
fields,
generics,
false,
quote!(_serde::ser::SerializeTupleStruct::serialize_field));
let type_name = item_attrs.name().serialize_name();
let len = serialize_stmts.len();
let let_mut = mut_if(len > 0);
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_struct(_serializer, #type_name, #len));
#(#serialize_stmts)*
_serde::ser::SerializeTupleStruct::end(__serde_state)
}
}
fn serialize_struct(ident: &syn::Ident,
generics: &syn::Generics,
fields: &[Field],
item_attrs: &attr::Item)
-> Fragment {
let serialize_fields =
serialize_struct_visitor(ident,
fields,
generics,
false,
quote!(_serde::ser::SerializeStruct::serialize_field));
let type_name = item_attrs.name().serialize_name();
let mut serialized_fields = fields.iter()
.filter(|&field| !field.attrs.skip_serializing())
.peekable();
let let_mut = mut_if(serialized_fields.peek().is_some());
let len = serialized_fields.map(|field| {
let ident = field.ident.clone().expect("struct has unnamed fields");
let field_expr = quote!(&self.#ident);
match field.attrs.skip_serializing_if() {
Some(path) => quote!(if #path(#field_expr) { 0 } else { 1 }),
None => quote!(1),
}
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(_serializer, #type_name, #len));
#(#serialize_fields)*
_serde::ser::SerializeStruct::end(__serde_state)
}
}
fn serialize_item_enum(ident: &syn::Ident,
generics: &syn::Generics,
variants: &[Variant],
item_attrs: &attr::Item)
-> Fragment {
let arms: Vec<_> = variants.iter()
.enumerate()
.map(|(variant_index, variant)| {
serialize_variant(ident,
generics,
variant,
variant_index,
item_attrs)
})
.collect();
quote_expr! {
match *self {
#(#arms)*
}
}
}
fn serialize_variant(ident: &syn::Ident,
generics: &syn::Generics,
variant: &Variant,
variant_index: usize,
item_attrs: &attr::Item)
-> Tokens {
let variant_ident = variant.ident.clone();
if variant.attrs.skip_serializing() {
let skipped_msg = format!("the enum variant {}::{} cannot be serialized",
ident, variant_ident);
let skipped_err = quote! {
_serde::export::Err(_serde::ser::Error::custom(#skipped_msg))
};
let fields_pat = match variant.style {
Style::Unit => quote!(),
Style::Newtype | Style::Tuple => quote!( (..) ),
Style::Struct => quote!( {..} ),
};
quote! {
#ident::#variant_ident #fields_pat => #skipped_err,
}
} else {
// variant wasn't skipped
let case = match variant.style {
Style::Unit => {
quote! {
#ident::#variant_ident
}
}
Style::Newtype => {
quote! {
#ident::#variant_ident(ref __field0)
}
}
Style::Tuple => {
let field_names = (0..variant.fields.len())
.map(|i| Ident::new(format!("__field{}", i)));
quote! {
#ident::#variant_ident(#(ref #field_names),*)
}
}
Style::Struct => {
let fields = variant.fields
.iter()
.map(|f| f.ident.clone().expect("struct variant has unnamed fields"));
quote! {
#ident::#variant_ident { #(ref #fields),* }
}
}
};
let body = Match(match *item_attrs.tag() {
attr::EnumTag::External => {
serialize_externally_tagged_variant(ident,
generics,
variant,
variant_index,
item_attrs)
}
attr::EnumTag::Internal { ref tag } => {
serialize_internally_tagged_variant(ident,
generics,
variant,
item_attrs,
tag)
}
attr::EnumTag::Adjacent { ref tag, ref content } => {
serialize_adjacently_tagged_variant(ident,
generics,
variant,
item_attrs,
tag,
content)
}
attr::EnumTag::None => serialize_untagged_variant(ident, generics, variant, item_attrs),
});
quote! {
#case => #body
}
}
}
fn serialize_externally_tagged_variant(ident: &syn::Ident,
generics: &syn::Generics,
variant: &Variant,
variant_index: usize,
item_attrs: &attr::Item)
-> Fragment {
let type_name = item_attrs.name().serialize_name();
let variant_name = variant.attrs.name().serialize_name();
match variant.style {
Style::Unit => {
quote_expr! {
_serde::Serializer::serialize_unit_variant(
_serializer,
#type_name,
#variant_index,
#variant_name,
)
}
}
Style::Newtype => {
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(ident, generics, field.ty, path, field_expr);
}
quote_expr! {
_serde::Serializer::serialize_newtype_variant(
_serializer,
#type_name,
#variant_index,
#variant_name,
#field_expr,
)
}
}
Style::Tuple => {
serialize_tuple_variant(TupleVariant::ExternallyTagged {
type_name: type_name,
variant_index: variant_index,
variant_name: variant_name,
},
ident,
generics,
&variant.fields)
}
Style::Struct => {
serialize_struct_variant(StructVariant::ExternallyTagged {
variant_index: variant_index,
variant_name: variant_name,
},
ident,
generics,
&variant.fields,
&type_name)
}
}
}
fn serialize_internally_tagged_variant(ident: &syn::Ident,
generics: &syn::Generics,
variant: &Variant,
item_attrs: &attr::Item,
tag: &str)
-> Fragment {
let type_name = item_attrs.name().serialize_name();
let variant_name = variant.attrs.name().serialize_name();
let enum_ident_str = ident.as_ref();
let variant_ident_str = variant.ident.as_ref();
match variant.style {
Style::Unit => {
quote_block! {
let mut __struct = try!(_serde::Serializer::serialize_struct(
_serializer, #type_name, 1));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
_serde::ser::SerializeStruct::end(__struct)
}
}
Style::Newtype => {
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(ident, generics, field.ty, path, field_expr);
}
quote_expr! {
_serde::ser::private::serialize_tagged_newtype(
_serializer,
#enum_ident_str,
#variant_ident_str,
#tag,
#variant_name,
#field_expr,
)
}
}
Style::Struct => {
serialize_struct_variant(StructVariant::InternallyTagged {
tag: tag,
variant_name: variant_name,
},
ident,
generics,
&variant.fields,
&type_name)
}
Style::Tuple => unreachable!("checked in serde_codegen_internals"),
}
}
fn serialize_adjacently_tagged_variant(ident: &syn::Ident,
generics: &syn::Generics,
variant: &Variant,
item_attrs: &attr::Item,
tag: &str,
content: &str)
-> Fragment {
let type_name = item_attrs.name().serialize_name();
let variant_name = variant.attrs.name().serialize_name();
let inner = Stmts(match variant.style {
Style::Unit => {
return quote_block! {
let mut __struct = try!(_serde::Serializer::serialize_struct(
_serializer, #type_name, 1));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
_serde::ser::SerializeStruct::end(__struct)
};
}
Style::Newtype => {
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(ident, generics, field.ty, path, field_expr);
}
quote_expr! {
_serde::Serialize::serialize(#field_expr, _serializer)
}
}
Style::Tuple => {
serialize_tuple_variant(TupleVariant::Untagged,
ident,
generics,
&variant.fields)
}
Style::Struct => {
serialize_struct_variant(StructVariant::Untagged,
ident,
generics,
&variant.fields,
&variant_name)
}
});
let fields_ty = variant.fields.iter().map(|f| &f.ty);
let ref fields_ident: Vec<_> = match variant.style {
Style::Unit => unreachable!(),
Style::Newtype => vec![Ident::new("__field0")],
Style::Tuple => {
(0..variant.fields.len())
.map(|i| Ident::new(format!("__field{}", i)))
.collect()
}
Style::Struct => {
variant.fields
.iter()
.map(|f| f.ident.clone().expect("struct variant has unnamed fields"))
.collect()
}
};
let (_, ty_generics, where_clause) = generics.split_for_impl();
let wrapper_generics = bound::with_lifetime_bound(generics, "'__a");
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! {
struct __AdjacentlyTagged #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*),
phantom: _serde::export::PhantomData<#ident #ty_generics>,
}
impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause {
fn serialize<__S>(&self, _serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where __S: _serde::Serializer
{
let (#(#fields_ident,)*) = self.data;
#inner
}
}
let mut __struct = try!(_serde::Serializer::serialize_struct(
_serializer, #type_name, 2));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #content, &__AdjacentlyTagged {
data: (#(#fields_ident,)*),
phantom: _serde::export::PhantomData::<#ident #ty_generics>,
}));
_serde::ser::SerializeStruct::end(__struct)
}
}
fn serialize_untagged_variant(ident: &syn::Ident,
generics: &syn::Generics,
variant: &Variant,
item_attrs: &attr::Item)
-> Fragment {
match variant.style {
Style::Unit => {
quote_expr! {
_serde::Serializer::serialize_unit(_serializer)
}
}
Style::Newtype => {
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(ident, generics, field.ty, path, field_expr);
}
quote_expr! {
_serde::Serialize::serialize(#field_expr, _serializer)
}
}
Style::Tuple => {
serialize_tuple_variant(TupleVariant::Untagged, ident, generics, &variant.fields)
}
Style::Struct => {
let type_name = item_attrs.name().serialize_name();
serialize_struct_variant(StructVariant::Untagged,
ident,
generics,
&variant.fields,
&type_name)
}
}
}
enum TupleVariant {
ExternallyTagged {
type_name: String,
variant_index: usize,
variant_name: String,
},
Untagged,
}
fn serialize_tuple_variant(context: TupleVariant,
ident: &syn::Ident,
generics: &syn::Generics,
fields: &[Field])
-> Fragment {
let method = match context {
TupleVariant::ExternallyTagged { .. } => {
quote!(_serde::ser::SerializeTupleVariant::serialize_field)
}
TupleVariant::Untagged => quote!(_serde::ser::SerializeTuple::serialize_element),
};
let serialize_stmts =
serialize_tuple_struct_visitor(ident, fields, generics, true, method);
let len = serialize_stmts.len();
let let_mut = mut_if(len > 0);
match context {
TupleVariant::ExternallyTagged { type_name, variant_index, variant_name } => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_variant(
_serializer,
#type_name,
#variant_index,
#variant_name,
#len));
#(#serialize_stmts)*
_serde::ser::SerializeTupleVariant::end(__serde_state)
}
}
TupleVariant::Untagged => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple(
_serializer,
#len));
#(#serialize_stmts)*
_serde::ser::SerializeTuple::end(__serde_state)
}
}
}
}
enum StructVariant<'a> {
ExternallyTagged {
variant_index: usize,
variant_name: String,
},
InternallyTagged { tag: &'a str, variant_name: String },
Untagged,
}
fn serialize_struct_variant<'a>(context: StructVariant<'a>,
ident: &syn::Ident,
generics: &syn::Generics,
fields: &[Field],
name: &str)
-> Fragment {
let method = match context {
StructVariant::ExternallyTagged { .. } => {
quote!(_serde::ser::SerializeStructVariant::serialize_field)
}
StructVariant::InternallyTagged { .. } |
StructVariant::Untagged => quote!(_serde::ser::SerializeStruct::serialize_field),
};
let serialize_fields = serialize_struct_visitor(ident, fields, generics, true, method);
let mut serialized_fields = fields.iter()
.filter(|&field| !field.attrs.skip_serializing())
.peekable();
let let_mut = mut_if(serialized_fields.peek().is_some());
let len = serialized_fields.map(|field| {
let ident = field.ident.clone().expect("struct has unnamed fields");
match field.attrs.skip_serializing_if() {
Some(path) => quote!(if #path(#ident) { 0 } else { 1 }),
None => quote!(1),
}
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
match context {
StructVariant::ExternallyTagged { variant_index, variant_name } => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct_variant(
_serializer,
#name,
#variant_index,
#variant_name,
#len,
));
#(#serialize_fields)*
_serde::ser::SerializeStructVariant::end(__serde_state)
}
}
StructVariant::InternallyTagged { tag, variant_name } => {
quote_block! {
let mut __serde_state = try!(_serde::Serializer::serialize_struct(
_serializer,
#name,
#len + 1,
));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __serde_state,
#tag,
#variant_name,
));
#(#serialize_fields)*
_serde::ser::SerializeStruct::end(__serde_state)
}
}
StructVariant::Untagged => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(
_serializer,
#name,
#len,
));
#(#serialize_fields)*
_serde::ser::SerializeStruct::end(__serde_state)
}
}
}
}
fn serialize_tuple_struct_visitor(ident: &syn::Ident,
fields: &[Field],
generics: &syn::Generics,
is_enum: bool,
func: Tokens)
-> Vec<Tokens> {
fields.iter()
.enumerate()
.map(|(i, field)| {
let mut field_expr = if is_enum {
let id = Ident::new(format!("__field{}", i));
quote!(#id)
} else {
let i = Ident::new(i);
quote!(&self.#i)
};
let skip = field.attrs
.skip_serializing_if()
.map(|path| quote!(#path(#field_expr)));
if let Some(path) = field.attrs.serialize_with() {
field_expr =
wrap_serialize_with(ident, generics, field.ty, path, field_expr);
}
let ser = quote! {
try!(#func(&mut __serde_state, #field_expr));
};
match skip {
None => ser,
Some(skip) => quote!(if !#skip { #ser }),
}
})
.collect()
}
fn serialize_struct_visitor(ident: &syn::Ident,
fields: &[Field],
generics: &syn::Generics,
is_enum: bool,
func: Tokens)
-> Vec<Tokens> {
fields.iter()
.filter(|&field| !field.attrs.skip_serializing())
.map(|field| {
let field_ident = field.ident.clone().expect("struct has unnamed field");
let mut field_expr = if is_enum {
quote!(#field_ident)
} else {
quote!(&self.#field_ident)
};
let key_expr = field.attrs.name().serialize_name();
let skip = field.attrs
.skip_serializing_if()
.map(|path| quote!(#path(#field_expr)));
if let Some(path) = field.attrs.serialize_with() {
field_expr =
wrap_serialize_with(ident, generics, field.ty, path, field_expr)
}
let ser = quote! {
try!(#func(&mut __serde_state, #key_expr, #field_expr));
};
match skip {
None => ser,
Some(skip) => quote!(if !#skip { #ser }),
}
})
.collect()
}
fn wrap_serialize_with(ident: &syn::Ident,
generics: &syn::Generics,
field_ty: &syn::Ty,
serialize_with: &syn::Path,
value: Tokens)
-> Tokens {
let (_, ty_generics, where_clause) = generics.split_for_impl();
let wrapper_generics = bound::with_lifetime_bound(generics, "'__a");
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote!({
struct __SerializeWith #wrapper_impl_generics #where_clause {
value: &'__a #field_ty,
phantom: _serde::export::PhantomData<#ident #ty_generics>,
}
impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause {
fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where __S: _serde::Serializer
{
#serialize_with(self.value, __s)
}
}
&__SerializeWith {
value: #value,
phantom: _serde::export::PhantomData::<#ident #ty_generics>,
}
})
}
// Serialization of an empty struct results in code like:
//
// let mut __serde_state = try!(serializer.serialize_struct("S", 0));
// _serde::ser::SerializeStruct::end(__serde_state)
//
// where we want to omit the `mut` to avoid a warning.
fn mut_if(is_mut: bool) -> Option<Tokens> {
if is_mut { Some(quote!(mut)) } else { None }
}
-30
View File
@@ -1,30 +0,0 @@
extern crate compiletest_rs as compiletest;
use std::path::PathBuf;
use std::env::var;
fn run_mode(mode: &'static str) {
let mut config = compiletest::default_config();
let cfg_mode = mode.parse().ok().expect("Invalid mode");
config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps/".to_owned());
if let Ok(name) = var::<&str>("TESTNAME") {
let s : String = name.to_owned();
config.filter = Some(s)
}
config.mode = cfg_mode;
config.src_base = PathBuf::from(format!("tests/{}", mode));
compiletest::run_tests(&config);
}
#[test]
fn compile_fail() {
run_mode("compile-fail");
}
#[test]
fn run_pass() {
run_mode("run-pass");
}
-10
View File
@@ -1,10 +0,0 @@
#![feature(test)]
#[macro_use]
extern crate serde_derive;
extern crate test;
include!("../../testing/tests/test.rs.in");
mod compile_tests;
+7 -4
View File
@@ -1,15 +1,18 @@
[package]
name = "serde_test"
version = "0.8.22"
version = "0.9.8"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://docs.serde.rs/serde_test/"
readme = "../README.md"
keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
readme = "../README.md"
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
[dependencies]
serde = { version = "0.8.22", path = "../serde" }
serde = { version = "0.9", path = "../serde" }
[badges]
travis-ci = { repository = "serde-rs/serde" }
+1
View File
@@ -0,0 +1 @@
../LICENSE-APACHE
+1
View File
@@ -0,0 +1 @@
../LICENSE-MIT
+1
View File
@@ -0,0 +1 @@
../README.md
+5 -5
View File
@@ -8,14 +8,14 @@ use token::Token;
use std::fmt::Debug;
pub fn assert_tokens<T>(value: &T, tokens: &[Token<'static>])
where T: Serialize + Deserialize + PartialEq + Debug,
where T: Serialize + Deserialize + PartialEq + Debug
{
assert_ser_tokens(value, tokens);
assert_de_tokens(value, tokens);
}
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
where T: Serialize,
where T: Serialize
{
let mut ser = Serializer::new(tokens.iter());
assert_eq!(Serialize::serialize(value, &mut ser), Ok(()));
@@ -24,7 +24,7 @@ pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
/// Expect an error serializing `T`.
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: Error)
where T: Serialize + PartialEq + Debug,
where T: Serialize + PartialEq + Debug
{
let mut ser = Serializer::new(tokens.iter());
let v: Result<(), Error> = Serialize::serialize(value, &mut ser);
@@ -33,7 +33,7 @@ pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: Error)
}
pub fn assert_de_tokens<T>(value: &T, tokens: &[Token<'static>])
where T: Deserialize + PartialEq + Debug,
where T: Deserialize + PartialEq + Debug
{
let mut de = Deserializer::new(tokens.to_vec().into_iter());
let v: Result<T, Error> = Deserialize::deserialize(&mut de);
@@ -43,7 +43,7 @@ pub fn assert_de_tokens<T>(value: &T, tokens: &[Token<'static>])
/// Expect an error deserializing tokens into a `T`.
pub fn assert_de_tokens_error<T>(tokens: &[Token<'static>], error: Error)
where T: Deserialize + PartialEq + Debug,
where T: Deserialize + PartialEq + Debug
{
let mut de = Deserializer::new(tokens.to_vec().into_iter());
let v: Result<T, Error> = Deserialize::deserialize(&mut de);
+218 -621
View File
File diff suppressed because it is too large Load Diff
+21 -60
View File
@@ -1,4 +1,5 @@
use std::{error, fmt};
use std::error;
use std::fmt::{self, Display};
use serde::{ser, de};
@@ -6,82 +7,42 @@ use token::Token;
#[derive(Clone, PartialEq, Debug)]
pub enum Error {
// Shared
Custom(String),
InvalidValue(String),
// De
EndOfStream,
InvalidType(de::Type),
InvalidLength(usize),
UnknownVariant(String),
UnknownField(String),
MissingField(&'static str),
DuplicateField(&'static str),
Message(String),
InvalidName(&'static str),
UnexpectedToken(Token<'static>),
EndOfTokens,
}
impl ser::Error for Error {
fn custom<T: Into<String>>(msg: T) -> Error {
Error::Custom(msg.into())
}
fn invalid_value(msg: &str) -> Error {
Error::InvalidValue(msg.to_owned())
fn custom<T: Display>(msg: T) -> Error {
Error::Message(msg.to_string())
}
}
impl de::Error for Error {
fn custom<T: Into<String>>(msg: T) -> Error {
Error::Custom(msg.into())
}
fn end_of_stream() -> Error {
Error::EndOfStream
}
fn invalid_type(ty: de::Type) -> Error {
Error::InvalidType(ty)
}
fn invalid_value(msg: &str) -> Error {
Error::InvalidValue(msg.to_owned())
}
fn invalid_length(len: usize) -> Error {
Error::InvalidLength(len)
}
fn unknown_variant(variant: &str) -> Error {
Error::UnknownVariant(variant.to_owned())
}
fn unknown_field(field: &str) -> Error {
Error::UnknownField(field.to_owned())
}
fn missing_field(field: &'static str) -> Error {
Error::MissingField(field)
}
fn duplicate_field(field: &'static str) -> Error {
Error::DuplicateField(field)
fn custom<T: Display>(msg: T) -> Error {
Error::Message(msg.to_string())
}
}
impl fmt::Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
formatter.write_str(format!("{:?}", self).as_ref())
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Message(ref msg) => formatter.write_str(msg),
Error::InvalidName(name) => write!(formatter, "invalid name `{}`", name),
Error::UnexpectedToken(_) => formatter.write_str("unexpected token"),
Error::EndOfTokens => formatter.write_str("end of tokens"),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
"Serde Error"
}
fn cause(&self) -> Option<&error::Error> {
None
match *self {
Error::Message(ref msg) => msg,
Error::InvalidName(_) => "invalid name",
Error::UnexpectedToken(_) => "unexpected token",
Error::EndOfTokens => "end of tokens",
}
}
}
+3 -7
View File
@@ -1,13 +1,9 @@
#[macro_use]
extern crate serde;
mod assert;
pub use assert::{
assert_tokens,
assert_ser_tokens,
assert_ser_tokens_error,
assert_de_tokens,
assert_de_tokens_error,
};
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error, assert_de_tokens,
assert_de_tokens_error};
mod ser;
pub use ser::Serializer;
+237 -197
View File
@@ -1,22 +1,19 @@
use std::marker::PhantomData;
use serde::ser::{
self,
Serialize,
};
use serde::{ser, Serialize};
use error::Error;
use token::Token;
pub struct Serializer<'a, I>
where I: Iterator<Item=&'a Token<'a>>,
where I: Iterator<Item = &'a Token<'a>>
{
tokens: I,
phantom: PhantomData<&'a Token<'a>>,
}
impl<'a, I> Serializer<'a, I>
where I: Iterator<Item=&'a Token<'a>>,
where I: Iterator<Item = &'a Token<'a>>
{
pub fn new(tokens: I) -> Serializer<'a, I> {
Serializer {
@@ -30,294 +27,337 @@ impl<'a, I> Serializer<'a, I>
}
}
impl<'a, I> ser::Serializer for Serializer<'a, I>
where I: Iterator<Item=&'a Token<'a>>,
impl<'s, 'a, I> ser::Serializer for &'s mut Serializer<'a, I>
where I: Iterator<Item = &'a Token<'a>>
{
type Ok = ();
type Error = Error;
type MapState = ();
type SeqState = ();
type TupleState = ();
type TupleStructState = ();
type TupleVariantState = ();
type StructState = ();
type StructVariantState = ();
fn serialize_unit(&mut self) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::Unit));
Ok(())
}
type SerializeSeq = Self;
type SerializeTuple = Self;
type SerializeTupleStruct = Self;
type SerializeTupleVariant = Self;
type SerializeMap = Self;
type SerializeStruct = Self;
type SerializeStructVariant = Self;
fn serialize_newtype_variant<T>(&mut self,
name: &str,
_variant_index: usize,
variant: &str,
value: T) -> Result<(), Error>
where T: Serialize,
{
assert_eq!(self.tokens.next(), Some(&Token::EnumNewType(name, variant)));
value.serialize(self)
}
fn serialize_unit_struct(&mut self, name: &str) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::UnitStruct(name)));
Ok(())
}
fn serialize_unit_variant(&mut self,
name: &str,
_variant_index: usize,
variant: &str) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::EnumUnit(name, variant)));
Ok(())
}
fn serialize_bool(&mut self, v: bool) -> Result<(), Error> {
fn serialize_bool(self, v: bool) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::Bool(v)));
Ok(())
}
fn serialize_isize(&mut self, v: isize) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::Isize(v)));
Ok(())
}
fn serialize_i8(&mut self, v: i8) -> Result<(), Error> {
fn serialize_i8(self, v: i8) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::I8(v)));
Ok(())
}
fn serialize_i16(&mut self, v: i16) -> Result<(), Error> {
fn serialize_i16(self, v: i16) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::I16(v)));
Ok(())
}
fn serialize_i32(&mut self, v: i32) -> Result<(), Error> {
fn serialize_i32(self, v: i32) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::I32(v)));
Ok(())
}
fn serialize_i64(&mut self, v: i64) -> Result<(), Error> {
fn serialize_i64(self, v: i64) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::I64(v)));
Ok(())
}
fn serialize_usize(&mut self, v: usize) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::Usize(v)));
Ok(())
}
fn serialize_u8(&mut self, v: u8) -> Result<(), Error> {
fn serialize_u8(self, v: u8) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::U8(v)));
Ok(())
}
fn serialize_u16(&mut self, v: u16) -> Result<(), Error> {
fn serialize_u16(self, v: u16) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::U16(v)));
Ok(())
}
fn serialize_u32(&mut self, v: u32) -> Result<(), Error> {
fn serialize_u32(self, v: u32) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::U32(v)));
Ok(())
}
fn serialize_u64(&mut self, v: u64) -> Result<(), Error> {
fn serialize_u64(self, v: u64) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::U64(v)));
Ok(())
}
fn serialize_f32(&mut self, v: f32) -> Result<(), Error> {
fn serialize_f32(self, v: f32) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::F32(v)));
Ok(())
}
fn serialize_f64(&mut self, v: f64) -> Result<(), Error> {
fn serialize_f64(self, v: f64) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::F64(v)));
Ok(())
}
fn serialize_char(&mut self, v: char) -> Result<(), Error> {
fn serialize_char(self, v: char) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::Char(v)));
Ok(())
}
fn serialize_str(&mut self, v: &str) -> Result<(), Error> {
fn serialize_str(self, v: &str) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::Str(v)));
Ok(())
}
fn serialize_none(&mut self) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::Option(false)));
fn serialize_bytes(self, value: &[u8]) -> Result<(), Self::Error> {
assert_eq!(self.tokens.next(), Some(&Token::Bytes(value)));
Ok(())
}
fn serialize_some<V>(&mut self, value: V) -> Result<(), Error>
where V: Serialize,
{
assert_eq!(self.tokens.next(), Some(&Token::Option(true)));
value.serialize(self)
}
fn serialize_seq<'b>(&'b mut self, len: Option<usize>) -> Result<(), Error>
{
assert_eq!(self.tokens.next(), Some(&Token::SeqStart(len)));
fn serialize_unit(self) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::Unit));
Ok(())
}
fn serialize_seq_elt<T>(&mut self, _: &mut (), value: T) -> Result<(), Error>
fn serialize_unit_struct(self, name: &str) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::UnitStruct(name)));
Ok(())
}
fn serialize_unit_variant(self,
name: &str,
_variant_index: usize,
variant: &str)
-> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::EnumUnit(name, variant)));
Ok(())
}
fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<(), Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::SeqSep));
value.serialize(self)
}
fn serialize_seq_end(&mut self, _: ()) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::SeqEnd));
Ok(())
}
fn serialize_seq_fixed_size(&mut self, len: usize) -> Result<(), Error>
{
assert_eq!(self.tokens.next(), Some(&Token::SeqArrayStart(len)));
Ok(())
}
fn serialize_tuple(&mut self, len: usize) -> Result<(), Error>
{
assert_eq!(self.tokens.next(), Some(&Token::TupleStart(len)));
Ok(())
}
fn serialize_tuple_elt<T>(&mut self, _: &mut (), value: T) -> Result<(), Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::TupleSep));
value.serialize(self)
}
fn serialize_tuple_end(&mut self, _: ()) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::TupleEnd));
Ok(())
}
fn serialize_newtype_struct<T>(&mut self,
name: &'static str,
value: T) -> Result<(), Error>
where T: Serialize,
{
assert_eq!(self.tokens.next(), Some(&Token::StructNewType(name)));
value.serialize(self)
}
fn serialize_tuple_struct(&mut self, name: &'static str, len: usize) -> Result<(), Error>
{
assert_eq!(self.tokens.next(), Some(&Token::TupleStructStart(name, len)));
Ok(())
}
fn serialize_tuple_struct_elt<T>(&mut self, _: &mut (), value: T) -> Result<(), Error>
fn serialize_newtype_variant<T: ?Sized>(self,
name: &str,
_variant_index: usize,
variant: &str,
value: &T)
-> Result<(), Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::TupleStructSep));
assert_eq!(self.tokens.next(), Some(&Token::EnumNewType(name, variant)));
value.serialize(self)
}
fn serialize_tuple_struct_end(&mut self, _: ()) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::TupleStructEnd));
fn serialize_none(self) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::Option(false)));
Ok(())
}
fn serialize_tuple_variant(&mut self,
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<(), Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::Option(true)));
value.serialize(self)
}
fn serialize_seq(self, len: Option<usize>) -> Result<Self, Error> {
assert_eq!(self.tokens.next(), Some(&Token::SeqStart(len)));
Ok(self)
}
fn serialize_seq_fixed_size(self, len: usize) -> Result<Self, Error> {
assert_eq!(self.tokens.next(), Some(&Token::SeqArrayStart(len)));
Ok(self)
}
fn serialize_tuple(self, len: usize) -> Result<Self, Error> {
assert_eq!(self.tokens.next(), Some(&Token::TupleStart(len)));
Ok(self)
}
fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result<Self, Error> {
assert_eq!(self.tokens.next(),
Some(&Token::TupleStructStart(name, len)));
Ok(self)
}
fn serialize_tuple_variant(self,
name: &str,
_variant_index: usize,
variant: &str,
len: usize) -> Result<(), Error>
{
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqStart(name, variant, len)));
Ok(())
len: usize)
-> Result<Self, Error> {
assert_eq!(self.tokens.next(),
Some(&Token::EnumSeqStart(name, variant, len)));
Ok(self)
}
fn serialize_tuple_variant_elt<T>(&mut self, _: &mut (), value: T) -> Result<(), Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqSep));
value.serialize(self)
}
fn serialize_tuple_variant_end(&mut self, _: ()) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqEnd));
Ok(())
}
fn serialize_map(&mut self, len: Option<usize>) -> Result<(), Error>
{
fn serialize_map(self, len: Option<usize>) -> Result<Self, Error> {
assert_eq!(self.tokens.next(), Some(&Token::MapStart(len)));
Ok(())
Ok(self)
}
fn serialize_map_key<T>(&mut self, _: &mut (), key: T) -> Result<(), Self::Error> where T: Serialize {
assert_eq!(self.tokens.next(), Some(&Token::MapSep));
key.serialize(self)
}
fn serialize_map_value<T>(&mut self, _: &mut (), value: T) -> Result<(), Self::Error> where T: Serialize {
value.serialize(self)
}
fn serialize_map_end(&mut self, _: ()) -> Result<(), Self::Error> {
assert_eq!(self.tokens.next(), Some(&Token::MapEnd));
Ok(())
}
fn serialize_struct(&mut self, name: &str, len: usize) -> Result<(), Error>
{
fn serialize_struct(self, name: &str, len: usize) -> Result<Self, Error> {
assert_eq!(self.tokens.next(), Some(&Token::StructStart(name, len)));
Ok(())
Ok(self)
}
fn serialize_struct_elt<V>(&mut self, _: &mut (), key: &'static str, value: V) -> Result<(), Self::Error> where V: Serialize {
assert_eq!(self.tokens.next(), Some(&Token::StructSep));
try!(key.serialize(self));
value.serialize(self)
}
fn serialize_struct_end(&mut self, _: ()) -> Result<(), Self::Error> {
assert_eq!(self.tokens.next(), Some(&Token::StructEnd));
Ok(())
}
fn serialize_struct_variant(&mut self,
fn serialize_struct_variant(self,
name: &str,
_variant_index: usize,
variant: &str,
len: usize) -> Result<(), Error>
{
assert_eq!(self.tokens.next(), Some(&Token::EnumMapStart(name, variant, len)));
len: usize)
-> Result<Self, Error> {
assert_eq!(self.tokens.next(),
Some(&Token::EnumMapStart(name, variant, len)));
Ok(self)
}
}
impl<'s, 'a, I> ser::SerializeSeq for &'s mut Serializer<'a, I>
where I: Iterator<Item = &'a Token<'a>>
{
type Ok = ();
type Error = Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::SeqSep));
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::SeqEnd));
Ok(())
}
}
fn serialize_struct_variant_elt<V>(&mut self, _: &mut (), key: &'static str, value: V) -> Result<(), Self::Error> where V: Serialize {
assert_eq!(self.tokens.next(), Some(&Token::EnumMapSep));
try!(key.serialize(self));
value.serialize(self)
impl<'s, 'a, I> ser::SerializeTuple for &'s mut Serializer<'a, I>
where I: Iterator<Item = &'a Token<'a>>
{
type Ok = ();
type Error = Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::TupleSep));
value.serialize(&mut **self)
}
fn serialize_struct_variant_end(&mut self, _: ()) -> Result<(), Self::Error> {
fn end(self) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::TupleEnd));
Ok(())
}
}
impl<'s, 'a, I> ser::SerializeTupleStruct for &'s mut Serializer<'a, I>
where I: Iterator<Item = &'a Token<'a>>
{
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::TupleStructSep));
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::TupleStructEnd));
Ok(())
}
}
impl<'s, 'a, I> ser::SerializeTupleVariant for &'s mut Serializer<'a, I>
where I: Iterator<Item = &'a Token<'a>>
{
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqSep));
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqEnd));
Ok(())
}
}
impl<'s, 'a, I> ser::SerializeMap for &'s mut Serializer<'a, I>
where I: Iterator<Item = &'a Token<'a>>
{
type Ok = ();
type Error = Error;
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::MapSep));
key.serialize(&mut **self)
}
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where T: Serialize
{
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Self::Error> {
assert_eq!(self.tokens.next(), Some(&Token::MapEnd));
Ok(())
}
}
impl<'s, 'a, I> ser::SerializeStruct for &'s mut Serializer<'a, I>
where I: Iterator<Item = &'a Token<'a>>
{
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self,
key: &'static str,
value: &T)
-> Result<(), Self::Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::StructSep));
try!(key.serialize(&mut **self));
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Self::Error> {
assert_eq!(self.tokens.next(), Some(&Token::StructEnd));
Ok(())
}
}
impl<'s, 'a, I> ser::SerializeStructVariant for &'s mut Serializer<'a, I>
where I: Iterator<Item = &'a Token<'a>>
{
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self,
key: &'static str,
value: &T)
-> Result<(), Self::Error>
where T: Serialize
{
assert_eq!(self.tokens.next(), Some(&Token::EnumMapSep));
try!(key.serialize(&mut **self));
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Self::Error> {
assert_eq!(self.tokens.next(), Some(&Token::EnumMapEnd));
Ok(())
}
fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error> {
let mut state = try!(self.serialize_seq(Some(value.len())));
for c in value {
try!(self.serialize_seq_elt(&mut state, c));
}
self.serialize_seq_end(state)
}
}
+1 -2
View File
@@ -1,12 +1,10 @@
#[derive(Clone, PartialEq, Debug)]
pub enum Token<'a> {
Bool(bool),
Isize(isize),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
Usize(usize),
U8(u8),
U16(u16),
U32(u32),
@@ -17,6 +15,7 @@ pub enum Token<'a> {
Str(&'a str),
String(String),
Bytes(&'a [u8]),
ByteBuf(Vec<u8>),
Option(bool),
+25
View File
@@ -0,0 +1,25 @@
[package]
name = "serde_test_suite"
version = "0.0.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
publish = false
[features]
unstable-testing = [
"compiletest_rs",
"serde/unstable-testing",
]
[dev-dependencies]
fnv = "1.0"
rustc-serialize = "0.3.16"
serde = { path = "../serde" }
serde_derive = { path = "../serde_derive" }
serde_test = { path = "../serde_test" }
[dependencies]
compiletest_rs = { version = "0.2", optional = true }
[[test]]
name = "test"
path = "tests/test.rs"
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "serde_test_suite_deps"
version = "0.0.0"
authors = ["David Tolnay <dtolnay@gmail.com>"]
publish = false
[workspace]
[dependencies]
serde = { path = "../../serde" }
serde_derive = { path = "../../serde_derive" }
View File
+8
View File
@@ -0,0 +1,8 @@
[package]
name = "serde_derive_tests_no_std"
version = "0.0.0"
publish = false
[dependencies]
serde = { path = "../../serde", default-features = false }
serde_derive = { path = "../../serde_derive" }
+52
View File
@@ -0,0 +1,52 @@
#![feature(lang_items, start, libc)]
#![no_std]
extern crate libc;
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
#[lang = "eh_personality"]
#[no_mangle]
pub extern fn rust_eh_personality() {}
#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern fn rust_eh_unwind_resume() {}
#[lang = "panic_fmt"]
#[no_mangle]
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
_file: &'static str,
_line: u32) -> ! {
unsafe {
libc::abort()
}
}
//////////////////////////////////////////////////////////////////////////////
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)]
struct Unit;
#[derive(Serialize, Deserialize)]
struct Newtype(u8);
#[derive(Serialize, Deserialize)]
struct Tuple(u8, u8);
#[derive(Serialize, Deserialize)]
struct Struct { f: u8 }
#[derive(Serialize, Deserialize)]
enum Enum {
Unit,
Newtype(u8),
Tuple(u8, u8),
Struct { f: u8 },
}
@@ -0,0 +1,8 @@
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
#[serde(default)] //~^ HELP: #[serde(default)] can only be used on structs
enum E {
S { f: u8 },
}
@@ -0,0 +1,8 @@
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
#[serde(default)] //~^ HELP: #[serde(default)] can only be used on structs
struct T(u8, u8);
fn main() { }
@@ -1,7 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: custom derive attribute panicked
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
struct S {
#[serde(rename="x", serialize="y")] //~^^ HELP: unknown serde field attribute `serialize`
x: (),
@@ -1,7 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: custom derive attribute panicked
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
struct S {
#[serde(rename="x")]
#[serde(rename(deserialize="y"))] //~^^^ HELP: duplicate serde attribute `rename`
@@ -1,7 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: custom derive attribute panicked
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
struct S {
#[serde(rename(serialize="x"), rename(serialize="y"))] //~^^ HELP: duplicate serde attribute `rename`
x: (),
@@ -1,7 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: custom derive attribute panicked
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
struct S {
#[serde(rename(serialize="x"))]
#[serde(rename="y")] //~^^^ HELP: duplicate serde attribute `rename`
@@ -1,7 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: custom derive attribute panicked
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
struct S {
#[serde(rename(serialize="x", serialize="y"))] //~^^ HELP: duplicate serde attribute `rename`
x: (),
@@ -1,7 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: custom derive attribute panicked
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
struct S {
#[serde(rename(serialize="x"))]
#[serde(rename(serialize="y"))] //~^^^ HELP: duplicate serde attribute `rename`
@@ -0,0 +1,10 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
struct S {
#[serde(with = "w", serialize_with = "s")] //~^^ HELP: duplicate serde attribute `serialize_with`
x: (),
}
fn main() {}
@@ -0,0 +1,10 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
#[serde(tag = "type")] //~^ HELP: #[serde(tag = "...")] cannot be used with tuple variants
enum E {
Tuple(u8, u8),
}
fn main() {}
@@ -0,0 +1,8 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
#[serde(tag = "type")] //~^ HELP: #[serde(tag = "...")] can only be used on enums
struct S;
fn main() {}
@@ -0,0 +1,12 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
#[serde(untagged)]
#[serde(tag = "type")] //~^^ HELP: enum cannot be both untagged and internally tagged
enum E {
A(u8),
B(String),
}
fn main() {}
@@ -0,0 +1,8 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
#[serde(untagged)] //~^ HELP: #[serde(untagged)] can only be used on enums
struct S;
fn main() {}
@@ -1,7 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)] //~ ERROR: custom derive attribute panicked
#[derive(Serialize, Deserialize)] //~ ERROR: proc-macro derive panicked
struct Test<'a> {
s: &'a str, //~^^ HELP: Serde does not support deserializing fields of type &str
}
@@ -1,7 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: custom derive attribute panicked
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
#[serde(abc="xyz")] //~^ HELP: unknown serde container attribute `abc`
struct A {
x: u32,
@@ -1,7 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: custom derive attribute panicked
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
struct C {
#[serde(abc="xyz")] //~^^ HELP: unknown serde field attribute `abc`
x: u32,
@@ -1,7 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: custom derive attribute panicked
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
enum E {
#[serde(abc="xyz")] //~^^ HELP: unknown serde variant attribute `abc`
V,
+26
View File
@@ -0,0 +1,26 @@
extern crate compiletest_rs as compiletest;
use std::env;
fn run_mode(mode: &'static str) {
let mut config = compiletest::default_config();
config.mode = mode.parse().expect("invalid mode");
config.target_rustcflags = Some("-L deps/target/debug/deps".to_owned());
if let Ok(name) = env::var("TESTNAME") {
config.filter = Some(name);
}
config.src_base = format!("tests/{}", mode).into();
compiletest::run_tests(&config);
}
#[test]
fn compile_fail() {
run_mode("compile-fail");
}
#[test]
fn run_pass() {
run_mode("run-pass");
}
@@ -1,31 +1,3 @@
#[macro_export]
macro_rules! declare_ser_tests {
($($name:ident { $($value:expr => $tokens:expr,)+ })+) => {
$(
#[test]
fn $name() {
$(
assert_ser_tokens(&$value, $tokens);
)+
}
)+
}
}
#[macro_export]
macro_rules! btreemap {
() => {
BTreeMap::new()
};
($($key:expr => $value:expr),+) => {
{
let mut map = BTreeMap::new();
$(map.insert($key, $value);)+
map
}
}
}
macro_rules! btreeset {
() => {
BTreeSet::new()
+23
View File
@@ -0,0 +1,23 @@
#![cfg_attr(feature = "unstable-testing", feature(test, non_ascii_idents))]
#[cfg(feature = "unstable-testing")]
extern crate test;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_test;
#[macro_use]
mod macros;
mod test_annotations;
mod test_bytes;
mod test_de;
mod test_gen;
mod test_macros;
mod test_ser;
#[cfg(feature = "unstable-testing")]
mod compiletest;
@@ -20,12 +20,12 @@ trait ShouldSkip: Sized {
}
trait SerializeWith: Sized {
fn serialize_with<S>(&self, ser: &mut S) -> Result<(), S::Error>
fn serialize_with<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where S: Serializer;
}
trait DeserializeWith: Sized {
fn deserialize_with<D>(de: &mut D) -> Result<Self, D::Error>
fn deserialize_with<D>(de: D) -> Result<Self, D::Error>
where D: Deserializer;
}
@@ -38,7 +38,7 @@ impl ShouldSkip for i32 {
}
impl SerializeWith for i32 {
fn serialize_with<S>(&self, ser: &mut S) -> Result<(), S::Error>
fn serialize_with<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
if *self == 123 {
@@ -50,7 +50,7 @@ impl SerializeWith for i32 {
}
impl DeserializeWith for i32 {
fn deserialize_with<D>(de: &mut D) -> Result<Self, D::Error>
fn deserialize_with<D>(de: D) -> Result<Self, D::Error>
where D: Deserializer
{
if try!(Deserialize::deserialize(de)) {
@@ -145,7 +145,7 @@ fn test_default_enum() {
assert_de_tokens(
&DefaultEnum::Struct { a1: 1, a2: 2, a3: 3, a4: 0, a5: 123 },
&[
Token::EnumMapStart("DefaultEnum", "Struct", 5),
Token::EnumMapStart("DefaultEnum", "Struct", 3),
Token::EnumMapSep,
Token::Str("a1"),
@@ -174,7 +174,7 @@ fn test_default_enum() {
assert_de_tokens(
&DefaultEnum::Struct { a1: 1, a2: 0, a3: 123, a4: 0, a5: 123 },
&[
Token::EnumMapStart("DefaultEnum", "Struct", 5),
Token::EnumMapStart("DefaultEnum", "Struct", 3),
Token::EnumMapSep,
Token::Str("a1"),
@@ -239,7 +239,7 @@ impl Default for NotDeserializeStruct {
}
impl DeserializeWith for NotDeserializeStruct {
fn deserialize_with<D>(_: &mut D) -> Result<Self, D::Error>
fn deserialize_with<D>(_: D) -> Result<Self, D::Error>
where D: Deserializer
{
panic!()
@@ -343,7 +343,7 @@ fn test_ignore_unknown() {
Token::StructSep,
Token::Str("whoops"),
],
Error::UnknownField("whoops".to_owned())
Error::Message("unknown field `whoops`, expected `a1`".to_owned())
);
}
@@ -642,7 +642,7 @@ struct NotSerializeStruct(i8);
enum NotSerializeEnum { Trouble }
impl SerializeWith for NotSerializeEnum {
fn serialize_with<S>(&self, ser: &mut S) -> Result<(), S::Error>
fn serialize_with<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
"trouble".serialize(ser)
@@ -905,7 +905,7 @@ fn test_missing_renamed_field_struct() {
Token::StructEnd,
],
Error::MissingField("a3"),
Error::Message("missing field `a3`".to_owned()),
);
assert_de_tokens_error::<RenameStructSerializeDeserialize>(
@@ -918,7 +918,7 @@ fn test_missing_renamed_field_struct() {
Token::StructEnd,
],
Error::MissingField("a5"),
Error::Message("missing field `a5`".to_owned()),
);
}
@@ -930,7 +930,7 @@ fn test_missing_renamed_field_enum() {
Token::EnumMapEnd,
],
Error::MissingField("b"),
Error::Message("missing field `b`".to_owned()),
);
assert_de_tokens_error::<RenameEnumSerializeDeserialize<i8>>(
@@ -943,7 +943,7 @@ fn test_missing_renamed_field_enum() {
Token::EnumMapEnd,
],
Error::MissingField("d"),
Error::Message("missing field `d`".to_owned()),
);
}
@@ -962,7 +962,7 @@ fn test_invalid_length_enum() {
Token::I32(1),
Token::EnumSeqEnd,
],
Error::InvalidLength(1),
Error::Message("invalid length 1, expected tuple of 3 elements".to_owned()),
);
assert_de_tokens_error::<InvalidLengthEnum>(
&[
@@ -971,6 +971,6 @@ fn test_invalid_length_enum() {
Token::I32(1),
Token::EnumSeqEnd,
],
Error::InvalidLength(1),
Error::Message("invalid length 1, expected tuple of 2 elements".to_owned()),
);
}
+55
View File
@@ -0,0 +1,55 @@
use serde::bytes::{ByteBuf, Bytes};
use serde_test::{assert_tokens, assert_ser_tokens, assert_de_tokens, Token};
#[test]
fn test_bytes() {
let empty = Bytes::new(&[]);
assert_ser_tokens(&empty, &[Token::Bytes(b"")]);
let buf = vec![65, 66, 67];
let bytes = Bytes::new(&buf);
assert_ser_tokens(&bytes, &[Token::Bytes(b"ABC")]);
}
#[test]
fn test_byte_buf() {
let empty = ByteBuf::new();
assert_tokens(&empty, &[Token::Bytes(b"")]);
assert_de_tokens(&empty, &[Token::ByteBuf(Vec::new())]);
assert_de_tokens(&empty, &[Token::Str("")]);
assert_de_tokens(&empty, &[Token::String(String::new())]);
assert_de_tokens(&empty, &[
Token::SeqStart(None),
Token::SeqEnd,
]);
assert_de_tokens(&empty, &[
Token::SeqStart(Some(0)),
Token::SeqEnd,
]);
let buf = ByteBuf::from(vec![65, 66, 67]);
assert_tokens(&buf, &[Token::Bytes(b"ABC")]);
assert_de_tokens(&buf, &[Token::ByteBuf(vec![65, 66, 67])]);
assert_de_tokens(&buf, &[Token::Str("ABC")]);
assert_de_tokens(&buf, &[Token::String("ABC".to_owned())]);
assert_de_tokens(&buf, &[
Token::SeqStart(None),
Token::SeqSep,
Token::U8(65),
Token::SeqSep,
Token::U8(66),
Token::SeqSep,
Token::U8(67),
Token::SeqEnd,
]);
assert_de_tokens(&buf, &[
Token::SeqStart(Some(3)),
Token::SeqSep,
Token::U8(65),
Token::SeqSep,
Token::U8(66),
Token::SeqSep,
Token::U8(67),
Token::SeqEnd,
]);
}
@@ -2,6 +2,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::net;
use std::path::PathBuf;
use std::time::Duration;
use std::default::Default;
use serde::Deserialize;
@@ -32,12 +33,56 @@ struct Struct {
c: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct StructDenyUnknown {
a: i32,
#[serde(skip_deserializing)]
b: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(default)]
struct StructDefault<T> {
a: i32,
b: T,
}
impl Default for StructDefault<String> {
fn default() -> Self {
StructDefault {
a: 100,
b: "default".to_string(),
}
}
}
#[derive(PartialEq, Debug, Deserialize)]
struct StructSkipAll {
#[serde(skip_deserializing)]
a: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct StructSkipAllDenyUnknown {
#[serde(skip_deserializing)]
a: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
enum Enum {
#[allow(dead_code)]
#[serde(skip_deserializing)]
Skipped,
Unit,
Simple(i32),
Seq(i32, i32, i32),
Map { a: i32, b: i32, c: i32 },
}
#[derive(PartialEq, Debug, Deserialize)]
enum EnumSkipAll {
#[allow(dead_code)]
#[serde(skip_deserializing)]
Skipped,
@@ -69,7 +114,7 @@ macro_rules! declare_tests {
}
macro_rules! declare_error_tests {
($($name:ident<$target:ident> { $tokens:expr, $expected:expr, })+) => {
($($name:ident<$target:ty> { $tokens:expr, $expected:expr, })+) => {
$(
#[test]
fn $name() {
@@ -127,12 +172,10 @@ declare_tests! {
false => &[Token::Bool(false)],
}
test_isize {
0isize => &[Token::Isize(0)],
0isize => &[Token::I8(0)],
0isize => &[Token::I16(0)],
0isize => &[Token::I32(0)],
0isize => &[Token::I64(0)],
0isize => &[Token::Usize(0)],
0isize => &[Token::U8(0)],
0isize => &[Token::U16(0)],
0isize => &[Token::U32(0)],
@@ -141,14 +184,12 @@ declare_tests! {
0isize => &[Token::F64(0.)],
}
test_ints {
0isize => &[Token::Isize(0)],
0i8 => &[Token::I8(0)],
0i16 => &[Token::I16(0)],
0i32 => &[Token::I32(0)],
0i64 => &[Token::I64(0)],
}
test_uints {
0usize => &[Token::Usize(0)],
0u8 => &[Token::U8(0)],
0u16 => &[Token::U16(0)],
0u32 => &[Token::U32(0)],
@@ -201,7 +242,7 @@ declare_tests! {
],
() => &[
Token::TupleStructStart("Anything", 0),
Token::SeqEnd,
Token::TupleStructEnd,
],
}
test_unit_struct {
@@ -306,7 +347,7 @@ declare_tests! {
],
BTreeSet::<isize>::new() => &[
Token::TupleStructStart("Anything", 0),
Token::SeqEnd,
Token::TupleStructEnd,
],
}
test_hashset {
@@ -334,7 +375,7 @@ declare_tests! {
],
HashSet::<isize>::new() => &[
Token::TupleStructStart("Anything", 0),
Token::SeqEnd,
Token::TupleStructEnd,
],
hashset![FnvHasher @ 1, 2, 3] => &[
Token::SeqStart(Some(3)),
@@ -384,7 +425,7 @@ declare_tests! {
],
Vec::<isize>::new() => &[
Token::TupleStructStart("Anything", 0),
Token::SeqEnd,
Token::TupleStructEnd,
],
}
test_array {
@@ -448,7 +489,7 @@ declare_tests! {
],
[0; 0] => &[
Token::TupleStructStart("Anything", 0),
Token::SeqEnd,
Token::TupleStructEnd,
],
}
test_tuple {
@@ -540,7 +581,7 @@ declare_tests! {
],
BTreeMap::<isize, isize>::new() => &[
Token::StructStart("Anything", 0),
Token::MapEnd,
Token::StructEnd,
],
}
test_hashmap {
@@ -594,7 +635,7 @@ declare_tests! {
],
HashMap::<isize, isize>::new() => &[
Token::StructStart("Anything", 0),
Token::MapEnd,
Token::StructEnd,
],
hashmap![FnvHasher @ 1 => 2, 3 => 4] => &[
Token::MapStart(Some(2)),
@@ -681,6 +722,46 @@ declare_tests! {
Token::StructEnd,
],
}
test_struct_skip_all {
StructSkipAll { a: 0 } => &[
Token::StructStart("StructSkipAll", 0),
Token::StructEnd,
],
StructSkipAll { a: 0 } => &[
Token::StructStart("StructSkipAll", 1),
Token::StructSep,
Token::Str("a"),
Token::I32(1),
Token::StructSep,
Token::Str("b"),
Token::I32(2),
Token::StructEnd,
],
}
test_struct_skip_all_deny_unknown {
StructSkipAllDenyUnknown { a: 0 } => &[
Token::StructStart("StructSkipAllDenyUnknown", 0),
Token::StructEnd,
],
}
test_struct_default {
StructDefault { a: 50, b: "overwritten".to_string() } => &[
Token::StructStart("StructDefault", 1),
Token::StructSep,
Token::Str("a"),
Token::I32(50),
Token::StructSep,
Token::Str("b"),
Token::String("overwritten".to_string()),
Token::StructEnd,
],
StructDefault { a: 100, b: "default".to_string() } => &[
Token::StructStart("StructDefault", 0),
Token::StructEnd,
],
}
test_enum_unit {
Enum::Unit => &[
Token::EnumUnit("Enum", "Unit"),
@@ -726,7 +807,7 @@ declare_tests! {
test_enum_unit_usize {
Enum::Unit => &[
Token::EnumStart("Enum"),
Token::Usize(0),
Token::U32(0),
Token::Unit,
],
}
@@ -802,17 +883,51 @@ fn test_net_ipaddr() {
}
declare_error_tests! {
test_unknown_field<StructDenyUnknown> {
&[
Token::StructStart("StructDenyUnknown", 2),
Token::StructSep,
Token::Str("a"),
Token::I32(0),
Token::StructSep,
Token::Str("d"),
],
Error::Message("unknown field `d`, expected `a`".to_owned()),
}
test_skipped_field_is_unknown<StructDenyUnknown> {
&[
Token::StructStart("StructDenyUnknown", 2),
Token::StructSep,
Token::Str("b"),
],
Error::Message("unknown field `b`, expected `a`".to_owned()),
}
test_skip_all_deny_unknown<StructSkipAllDenyUnknown> {
&[
Token::StructStart("StructSkipAllDenyUnknown", 1),
Token::StructSep,
Token::Str("a"),
],
Error::Message("unknown field `a`, there are no fields".to_owned()),
}
test_unknown_variant<Enum> {
&[
Token::EnumUnit("Enum", "Foo"),
],
Error::UnknownVariant("Foo".to_owned()),
Error::Message("unknown variant `Foo`, expected one of `Unit`, `Simple`, `Seq`, `Map`".to_owned()),
}
test_enum_skipped_variant<Enum> {
&[
Token::EnumUnit("Enum", "Skipped"),
],
Error::UnknownVariant("Skipped".to_owned()),
Error::Message("unknown variant `Skipped`, expected one of `Unit`, `Simple`, `Seq`, `Map`".to_owned()),
}
test_enum_skip_all<EnumSkipAll> {
&[
Token::EnumUnit("EnumSkipAll", "Skipped"),
],
Error::Message("unknown variant `Skipped`, there are no variants".to_owned()),
}
test_struct_seq_too_long<Struct> {
&[
@@ -833,7 +948,7 @@ declare_error_tests! {
Token::MapSep,
Token::Str("a"),
],
Error::DuplicateField("a"),
Error::Message("duplicate field `a`".to_owned()),
}
test_duplicate_field_enum<Enum> {
&[
@@ -845,6 +960,32 @@ declare_error_tests! {
Token::EnumMapSep,
Token::Str("a"),
],
Error::DuplicateField("a"),
Error::Message("duplicate field `a`".to_owned()),
}
test_enum_out_of_range<Enum> {
&[
Token::EnumStart("Enum"),
Token::U32(4),
Token::Unit,
],
Error::Message("invalid value: integer `4`, expected variant index 0 <= i < 4".into()),
}
test_short_tuple<(u8, u8, u8)> {
&[
Token::TupleStart(1),
Token::TupleSep,
Token::U8(1),
Token::TupleEnd,
],
Error::Message("invalid length 1, expected a tuple of size 3".into()),
}
test_short_array<[u8; 3]> {
&[
Token::SeqStart(Some(1)),
Token::SeqSep,
Token::U8(1),
Token::SeqEnd,
],
Error::Message("invalid length 1, expected an array of length 3".into()),
}
}
@@ -8,11 +8,15 @@ use self::serde::de::{Deserialize, Deserializer};
use std::borrow::Cow;
use std::marker::PhantomData;
use std::result::Result as StdResult;
// Try to trip up the generated code if it fails to use fully qualified paths.
#[allow(dead_code)]
struct Result;
use std::result::Result as StdResult;
#[allow(dead_code)]
struct Ok;
#[allow(dead_code)]
struct Err;
//////////////////////////////////////////////////////////////////////////
@@ -26,6 +30,14 @@ fn test_gen() {
}
assert::<With<i32>>();
#[derive(Serialize, Deserialize)]
struct WithTogether<T> {
t: T,
#[serde(with="both_x")]
x: X,
}
assert::<WithTogether<i32>>();
#[derive(Serialize, Deserialize)]
struct WithRef<'a, T: 'a> {
#[serde(skip_deserializing)]
@@ -202,6 +214,91 @@ fn test_gen() {
EmptyStruct {},
}
assert::<EmptyEnumVariant>();
#[cfg(feature = "unstable-testing")]
#[cfg_attr(feature = "unstable-testing", derive(Serialize, Deserialize))]
struct NonAsciiIdents {
σ: f64
}
#[derive(Serialize, Deserialize)]
struct EmptyBraced {}
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct EmptyBracedDenyUnknown {}
#[derive(Serialize, Deserialize)]
struct BracedSkipAll {
#[serde(skip_deserializing)]
f: u8,
}
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct BracedSkipAllDenyUnknown {
#[serde(skip_deserializing)]
f: u8,
}
#[cfg(feature = "unstable-testing")]
#[cfg_attr(feature = "unstable-testing", derive(Serialize, Deserialize))]
struct EmptyTuple();
#[cfg(feature = "unstable-testing")]
#[cfg_attr(feature = "unstable-testing", derive(Serialize, Deserialize))]
#[serde(deny_unknown_fields)]
struct EmptyTupleDenyUnknown();
#[derive(Serialize, Deserialize)]
struct TupleSkipAll(#[serde(skip_deserializing)] u8);
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8);
#[derive(Serialize, Deserialize)]
enum EmptyEnum {}
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
enum EmptyEnumDenyUnknown {}
#[derive(Serialize, Deserialize)]
enum EnumSkipAll {
#[serde(skip_deserializing)]
#[allow(dead_code)]
Variant,
}
#[cfg(feature = "unstable-testing")]
#[cfg_attr(feature = "unstable-testing", derive(Serialize, Deserialize))]
enum EmptyVariants {
Braced {},
Tuple(),
BracedSkip {
#[serde(skip_deserializing)]
f: u8,
},
TupleSkip(#[serde(skip_deserializing)] u8),
}
#[cfg(feature = "unstable-testing")]
#[cfg_attr(feature = "unstable-testing", derive(Serialize, Deserialize))]
#[serde(deny_unknown_fields)]
enum EmptyVariantsDenyUnknown {
Braced {},
Tuple(),
BracedSkip {
#[serde(skip_deserializing)]
f: u8,
},
TupleSkip(#[serde(skip_deserializing)] u8),
}
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct UnitDenyUnknown;
}
//////////////////////////////////////////////////////////////////////////
@@ -210,32 +307,36 @@ fn assert<T: Serialize + Deserialize>() {}
fn assert_ser<T: Serialize>() {}
trait SerializeWith {
fn serialize_with<S: Serializer>(_: &Self, _: &mut S) -> StdResult<(), S::Error>;
fn serialize_with<S: Serializer>(_: &Self, _: S) -> StdResult<S::Ok, S::Error>;
}
trait DeserializeWith: Sized {
fn deserialize_with<D: Deserializer>(_: &mut D) -> StdResult<Self, D::Error>;
fn deserialize_with<D: Deserializer>(_: D) -> StdResult<Self, D::Error>;
}
// Implements neither Serialize nor Deserialize
struct X;
pub struct X;
fn ser_x<S: Serializer>(_: &X, _: &mut S) -> StdResult<(), S::Error> {
pub fn ser_x<S: Serializer>(_: &X, _: S) -> StdResult<S::Ok, S::Error> {
unimplemented!()
}
fn de_x<D: Deserializer>(_: &mut D) -> StdResult<X, D::Error> {
pub fn de_x<D: Deserializer>(_: D) -> StdResult<X, D::Error> {
unimplemented!()
}
mod both_x {
pub use super::{ser_x as serialize, de_x as deserialize};
}
impl SerializeWith for X {
fn serialize_with<S: Serializer>(_: &Self, _: &mut S) -> StdResult<(), S::Error> {
fn serialize_with<S: Serializer>(_: &Self, _: S) -> StdResult<S::Ok, S::Error> {
unimplemented!()
}
}
impl DeserializeWith for X {
fn deserialize_with<D: Deserializer>(_: &mut D) -> StdResult<Self, D::Error> {
fn deserialize_with<D: Deserializer>(_: D) -> StdResult<Self, D::Error> {
unimplemented!()
}
}
@@ -1,11 +1,14 @@
extern crate serde_test;
use self::serde_test::{
Error,
Token,
assert_tokens,
assert_ser_tokens,
assert_de_tokens,
assert_de_tokens_error,
};
use std::collections::BTreeMap;
use std::marker::PhantomData;
// That tests that the derived Serialize implementation doesn't trigger
@@ -625,3 +628,444 @@ fn test_enum_state_field() {
]
);
}
#[test]
fn test_untagged_enum() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
enum Untagged {
A {
a: u8,
},
B {
b: u8,
},
C,
D(u8),
E(String),
F(u8, u8),
}
assert_tokens(
&Untagged::A { a: 1 },
&[
Token::StructStart("Untagged", 1),
Token::StructSep,
Token::Str("a"),
Token::U8(1),
Token::StructEnd,
]
);
assert_tokens(
&Untagged::B { b: 2 },
&[
Token::StructStart("Untagged", 1),
Token::StructSep,
Token::Str("b"),
Token::U8(2),
Token::StructEnd,
]
);
assert_tokens(
&Untagged::C,
&[
Token::Unit,
]
);
assert_tokens(
&Untagged::D(4),
&[
Token::U8(4),
]
);
assert_tokens(
&Untagged::E("e".to_owned()),
&[
Token::Str("e"),
]
);
assert_tokens(
&Untagged::F(1, 2),
&[
Token::TupleStart(2),
Token::TupleSep,
Token::U8(1),
Token::TupleSep,
Token::U8(2),
Token::TupleEnd,
]
);
assert_de_tokens_error::<Untagged>(
&[
Token::Option(false),
],
Error::Message("data did not match any variant of untagged enum Untagged".to_owned()),
);
assert_de_tokens_error::<Untagged>(
&[
Token::TupleStart(1),
Token::TupleSep,
Token::U8(1),
Token::TupleEnd,
],
Error::Message("data did not match any variant of untagged enum Untagged".to_owned()),
);
assert_de_tokens_error::<Untagged>(
&[
Token::TupleStart(3),
Token::TupleSep,
Token::U8(1),
Token::TupleSep,
Token::U8(2),
Token::TupleSep,
Token::U8(3),
Token::TupleEnd,
],
Error::Message("data did not match any variant of untagged enum Untagged".to_owned()),
);
}
#[test]
fn test_internally_tagged_enum() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Newtype(BTreeMap<String, String>);
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Struct {
f: u8,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type")]
enum InternallyTagged {
A {
a: u8,
},
B {
b: u8,
},
C,
D(BTreeMap<String, String>),
E(Newtype),
F(Struct),
}
assert_tokens(
&InternallyTagged::A { a: 1 },
&[
Token::StructStart("InternallyTagged", 2),
Token::StructSep,
Token::Str("type"),
Token::Str("A"),
Token::StructSep,
Token::Str("a"),
Token::U8(1),
Token::StructEnd,
]
);
assert_tokens(
&InternallyTagged::B { b: 2 },
&[
Token::StructStart("InternallyTagged", 2),
Token::StructSep,
Token::Str("type"),
Token::Str("B"),
Token::StructSep,
Token::Str("b"),
Token::U8(2),
Token::StructEnd,
]
);
assert_tokens(
&InternallyTagged::C,
&[
Token::StructStart("InternallyTagged", 1),
Token::StructSep,
Token::Str("type"),
Token::Str("C"),
Token::StructEnd,
]
);
assert_tokens(
&InternallyTagged::D(BTreeMap::new()),
&[
Token::MapStart(Some(1)),
Token::MapSep,
Token::Str("type"),
Token::Str("D"),
Token::MapEnd,
]
);
assert_tokens(
&InternallyTagged::E(Newtype(BTreeMap::new())),
&[
Token::MapStart(Some(1)),
Token::MapSep,
Token::Str("type"),
Token::Str("E"),
Token::MapEnd,
]
);
assert_tokens(
&InternallyTagged::F(Struct { f: 6 }),
&[
Token::StructStart("Struct", 2),
Token::StructSep,
Token::Str("type"),
Token::Str("F"),
Token::StructSep,
Token::Str("f"),
Token::U8(6),
Token::StructEnd,
]
);
assert_de_tokens_error::<InternallyTagged>(
&[
Token::MapStart(Some(0)),
Token::MapEnd,
],
Error::Message("missing field `type`".to_owned()),
);
assert_de_tokens_error::<InternallyTagged>(
&[
Token::MapStart(Some(1)),
Token::MapSep,
Token::Str("type"),
Token::Str("Z"),
Token::MapEnd,
],
Error::Message("unknown variant `Z`, expected one of `A`, `B`, `C`, `D`, `E`, `F`".to_owned()),
);
}
#[test]
fn test_adjacently_tagged_enum() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "t", content = "c")]
enum AdjacentlyTagged<T> {
Unit,
Newtype(T),
Tuple(u8, u8),
Struct { f: u8 },
}
// unit with no content
assert_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::StructStart("AdjacentlyTagged", 1),
Token::StructSep,
Token::Str("t"),
Token::Str("Unit"),
Token::StructEnd,
]
);
// unit with tag first
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::StructStart("AdjacentlyTagged", 1),
Token::StructSep,
Token::Str("t"),
Token::Str("Unit"),
Token::StructSep,
Token::Str("c"),
Token::Unit,
Token::StructEnd,
]
);
// unit with content first
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::StructStart("AdjacentlyTagged", 1),
Token::StructSep,
Token::Str("c"),
Token::Unit,
Token::StructSep,
Token::Str("t"),
Token::Str("Unit"),
Token::StructEnd,
]
);
// newtype with tag first
assert_tokens(
&AdjacentlyTagged::Newtype::<u8>(1),
&[
Token::StructStart("AdjacentlyTagged", 2),
Token::StructSep,
Token::Str("t"),
Token::Str("Newtype"),
Token::StructSep,
Token::Str("c"),
Token::U8(1),
Token::StructEnd,
]
);
// newtype with content first
assert_de_tokens(
&AdjacentlyTagged::Newtype::<u8>(1),
&[
Token::StructStart("AdjacentlyTagged", 2),
Token::StructSep,
Token::Str("c"),
Token::U8(1),
Token::StructSep,
Token::Str("t"),
Token::Str("Newtype"),
Token::StructEnd,
]
);
// tuple with tag first
assert_tokens(
&AdjacentlyTagged::Tuple::<u8>(1, 1),
&[
Token::StructStart("AdjacentlyTagged", 2),
Token::StructSep,
Token::Str("t"),
Token::Str("Tuple"),
Token::StructSep,
Token::Str("c"),
Token::TupleStart(2),
Token::TupleSep,
Token::U8(1),
Token::TupleSep,
Token::U8(1),
Token::TupleEnd,
Token::StructEnd,
]
);
// tuple with content first
assert_de_tokens(
&AdjacentlyTagged::Tuple::<u8>(1, 1),
&[
Token::StructStart("AdjacentlyTagged", 2),
Token::StructSep,
Token::Str("c"),
Token::TupleStart(2),
Token::TupleSep,
Token::U8(1),
Token::TupleSep,
Token::U8(1),
Token::TupleEnd,
Token::StructSep,
Token::Str("t"),
Token::Str("Tuple"),
Token::StructEnd,
]
);
// struct with tag first
assert_tokens(
&AdjacentlyTagged::Struct::<u8> { f: 1 },
&[
Token::StructStart("AdjacentlyTagged", 2),
Token::StructSep,
Token::Str("t"),
Token::Str("Struct"),
Token::StructSep,
Token::Str("c"),
Token::StructStart("Struct", 1),
Token::StructSep,
Token::Str("f"),
Token::U8(1),
Token::StructEnd,
Token::StructEnd,
]
);
// struct with content first
assert_de_tokens(
&AdjacentlyTagged::Struct::<u8> { f: 1 },
&[
Token::StructStart("AdjacentlyTagged", 2),
Token::StructSep,
Token::Str("c"),
Token::StructStart("Struct", 1),
Token::StructSep,
Token::Str("f"),
Token::U8(1),
Token::StructEnd,
Token::StructSep,
Token::Str("t"),
Token::Str("Struct"),
Token::StructEnd,
]
);
}
@@ -15,6 +15,9 @@ use self::serde_test::{
extern crate fnv;
use self::fnv::FnvHasher;
#[cfg(feature = "unstable")]
use serde::ser::iterator;
//////////////////////////////////////////////////////////////////////////
#[derive(Serialize)]
@@ -48,7 +51,20 @@ enum Enum {
//////////////////////////////////////////////////////////////////////////
declare_ser_tests! {
macro_rules! declare_tests {
($($name:ident { $($value:expr => $tokens:expr,)+ })+) => {
$(
#[test]
fn $name() {
$(
assert_ser_tokens(&$value, $tokens);
)+
}
)+
}
}
declare_tests! {
test_unit {
() => &[Token::Unit],
}
@@ -57,14 +73,12 @@ declare_ser_tests! {
false => &[Token::Bool(false)],
}
test_isizes {
0isize => &[Token::Isize(0)],
0i8 => &[Token::I8(0)],
0i16 => &[Token::I16(0)],
0i32 => &[Token::I32(0)],
0i64 => &[Token::I64(0)],
}
test_usizes {
0usize => &[Token::Usize(0)],
0u8 => &[Token::U8(0)],
0u16 => &[Token::U16(0)],
0u32 => &[Token::U32(0)],
@@ -369,6 +383,49 @@ declare_ser_tests! {
}
}
#[cfg(feature = "unstable")]
#[test]
fn test_iterator() {
assert_ser_tokens(iterator([0; 0].iter()), &[
Token::SeqStart(Some(0)),
Token::SeqEnd,
]);
assert_ser_tokens(iterator([1, 2, 3].iter()), &[
Token::SeqStart(Some(3)),
Token::SeqSep,
Token::I32(1),
Token::SeqSep,
Token::I32(2),
Token::SeqSep,
Token::I32(3),
Token::SeqEnd,
]);
assert_ser_tokens(iterator([1, 2, 3].iter().map(|x| x * 2)), &[
Token::SeqStart(Some(3)),
Token::SeqSep,
Token::I32(2),
Token::SeqSep,
Token::I32(4),
Token::SeqSep,
Token::I32(6),
Token::SeqEnd,
]);
assert_ser_tokens(iterator([1, 2, 3].iter().filter(|&x| x % 2 != 0)), &[
Token::SeqStart(None),
Token::SeqSep,
Token::I32(1),
Token::SeqSep,
Token::I32(3),
Token::SeqEnd,
]);
}
#[cfg(feature = "unstable")]
#[test]
fn test_net_ipaddr() {
@@ -386,7 +443,7 @@ fn test_cannot_serialize_paths() {
assert_ser_tokens_error(
&Path::new(path),
&[],
Error::InvalidValue("Path contains invalid UTF-8 characters".to_owned()));
Error::Message("path contains invalid UTF-8 characters".to_owned()));
let mut path_buf = PathBuf::new();
path_buf.push(path);
@@ -394,7 +451,7 @@ fn test_cannot_serialize_paths() {
assert_ser_tokens_error(
&path_buf,
&[],
Error::InvalidValue("Path contains invalid UTF-8 characters".to_owned()));
Error::Message("path contains invalid UTF-8 characters".to_owned()));
}
#[test]
@@ -402,17 +459,17 @@ fn test_enum_skipped() {
assert_ser_tokens_error(
&Enum::SkippedUnit,
&[],
Error::InvalidValue("The enum variant Enum::SkippedUnit cannot be serialized".to_owned()));
Error::Message("the enum variant Enum::SkippedUnit cannot be serialized".to_owned()));
assert_ser_tokens_error(
&Enum::SkippedOne(42),
&[],
Error::InvalidValue("The enum variant Enum::SkippedOne cannot be serialized".to_owned()));
Error::Message("the enum variant Enum::SkippedOne cannot be serialized".to_owned()));
assert_ser_tokens_error(
&Enum::SkippedSeq(1, 2),
&[],
Error::InvalidValue("The enum variant Enum::SkippedSeq cannot be serialized".to_owned()));
Error::Message("the enum variant Enum::SkippedSeq cannot be serialized".to_owned()));
assert_ser_tokens_error(
&Enum::SkippedMap { _a: 1, _b: 2 },
&[],
Error::InvalidValue("The enum variant Enum::SkippedMap cannot be serialized".to_owned()));
Error::Message("the enum variant Enum::SkippedMap cannot be serialized".to_owned()));
}
-32
View File
@@ -1,32 +0,0 @@
[package]
name = "serde_testing"
version = "0.8.22"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://docs.serde.rs/serde/"
readme = "README.md"
keywords = ["serialization"]
build = "build.rs"
publish = false
[features]
unstable-testing = ["clippy", "serde/unstable-testing", "serde_codegen/unstable-testing"]
[build-dependencies]
serde_codegen = { path = "../serde_codegen", features = ["with-syntex"] }
[dev-dependencies]
fnv = "1.0"
rustc-serialize = "^0.3.16"
serde = { path = "../serde" }
serde_test = { path = "../serde_test" }
[dependencies]
clippy = { version = "^0.*", optional = true }
[[test]]
name = "test"
path = "tests/test.rs"
-11
View File
@@ -1,11 +0,0 @@
extern crate serde_codegen;
use std::env;
use std::path::Path;
fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let src = Path::new("tests/test.rs.in");
let dst = Path::new(&out_dir).join("test.rs");
serde_codegen::expand(&src, &dst).unwrap();
}
-4
View File
@@ -1,4 +0,0 @@
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
include!(concat!(env!("OUT_DIR"), "/test.rs"));
-12
View File
@@ -1,12 +0,0 @@
extern crate serde;
extern crate serde_test;
#[macro_use]
mod macros;
mod test_annotations;
mod test_bytes;
mod test_de;
mod test_gen;
mod test_macros;
mod test_ser;

Some files were not shown because too many files have changed in this diff Show More