From ec8dd2f5a0eac20972c0a854038021b24c06a9dd Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 22 Jun 2014 10:33:45 -0400 Subject: [PATCH] Optimize serialization Serialization is now competitive with go's serialization, with ~60MB/s in the bench_logs test. --- LICENSE | 33 +++ LICENSE-APACHE | 201 +++++++++++++++ LICENSE-MIT | 25 ++ bench_log.rs | 381 +---------------------------- json.rs | 652 +++++++++++++++++++++---------------------------- ser.rs | 9 +- 6 files changed, 551 insertions(+), 750 deletions(-) create mode 100644 LICENSE create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..530309bd --- /dev/null +++ b/LICENSE @@ -0,0 +1,33 @@ +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 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. + diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 00000000..16fe87b0 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000..39d4bdb5 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/bench_log.rs b/bench_log.rs index 99395ca0..c99cb84d 100644 --- a/bench_log.rs +++ b/bench_log.rs @@ -71,21 +71,6 @@ impl, E> ser::Serializable for HttpProtocol { #[inline] fn serialize(&self, s: &mut S) -> Result<(), E> { s.serialize_uint(*self as uint) - /* - match *self { - HTTP_PROTOCOL_UNKNOWN => { - try!(s.serialize_EnumStart("HttpProtocol", "HTTP_PROTOCOL_UNKNOWN", 0))); - } - HTTP10 => { - try!(s.serialize_EnumStart("HttpProtocol", "HTTP10", 0))); - } - HTTP11 => { - try!(s.serialize_EnumStart("HttpProtocol", "HTTP11", 0))); - } - } - - s.serialize_end() - */ } } @@ -108,46 +93,6 @@ impl, E> ser::Serializable for HttpMethod { #[inline] fn serialize(&self, s: &mut S) -> Result<(), E> { s.serialize_uint(*self as uint) - /* - match *self { - METHOD_UNKNOWN => { - try!(s.serialize_EnumStart("HttpMethod", "METHOD_UNKNOWN", 0))); - } - GET => { - try!(s.serialize_EnumStart("HttpMethod", "GET", 0))); - } - - POST => { - try!(s.serialize_EnumStart("HttpMethod", "POST", 0))); - } - DELETE => { - try!(s.serialize_EnumStart("HttpMethod", "DELETE", 0))); - } - PUT => { - try!(s.serialize_EnumStart("HttpMethod", "PUT", 0))); - } - HEAD => { - try!(s.serialize_EnumStart("HttpMethod", "HEAD", 0))); - } - PURGE => { - try!(s.serialize_EnumStart("HttpMethod", "PURGE", 0))); - } - OPTIONS => { - try!(s.serialize_EnumStart("HttpMethod", "OPTIONS", 0))); - } - PROPFIND => { - try!(s.serialize_EnumStart("HttpMethod", "PROPFIND", 0))); - } - MKCOL => { - try!(s.serialize_EnumStart("HttpMethod", "MKCOL", 0))); - } - PATCH => { - try!(s.serialize_EnumStart("HttpMethod", "PATCH", 0))); - } - } - - s.serialize_end() - */ } } @@ -163,24 +108,6 @@ impl, E> ser::Serializable for CacheStatus { #[inline] fn serialize(&self, s: &mut S) -> Result<(), E> { s.serialize_uint(*self as uint) - /* - match *self { - CACHESTATUS_UNKNOWN => { - try!(s.serialize_EnumStart("CacheStatus", "CACHESTATUS_UNKNOWN", 0))); - } - Miss => { - try!(s.serialize_EnumStart("CacheStatus", "Miss", 0))); - } - Expired => { - try!(s.serialize_EnumStart("CacheStatus", "Expired", 0))); - } - Hit => { - try!(s.serialize_EnumStart("CacheStatus", "Hit", 0))); - } - } - - s.serialize_end() - */ } } @@ -224,21 +151,6 @@ impl, E> ser::Serializable for OriginProtocol { #[inline] fn serialize(&self, s: &mut S) -> Result<(), E> { s.serialize_uint(*self as uint) - /* - match *self { - ORIGIN_PROTOCOL_UNKNOWN => { - try!(s.serialize_EnumStart("OriginProtocol", "ORIGIN_PROTOCOL_UNKNOWN", 0))); - } - HTTP => { - try!(s.serialize_EnumStart("OriginProtocol", "HTTP", 0))); - } - HTTPS => { - try!(s.serialize_EnumStart("OriginProtocol", "HTTPS", 0))); - } - } - - s.serialize_end() - */ } } @@ -255,27 +167,6 @@ impl, E> ser::Serializable for ZonePlan { #[inline] fn serialize(&self, s: &mut S) -> Result<(), E> { s.serialize_uint(*self as uint) - /* - match *self { - ZONEPLAN_UNKNOWN => { - try!(s.serialize_EnumStart("ZonePlan", "ZONEPLAN_UNKNOWN", 0))); - } - FREE => { - try!(s.serialize_EnumStart("ZonePlan", "FREE", 0))); - } - PRO => { - try!(s.serialize_EnumStart("ZonePlan", "PRO", 0))); - } - BIZ => { - try!(s.serialize_EnumStart("ZonePlan", "BIZ", 0))); - } - ENT => { - try!(s.serialize_EnumStart("ZonePlan", "ENT", 0))); - } - } - - s.serialize_end() - */ } } @@ -543,268 +434,6 @@ impl, E> ser::Serializable for Country { #[inline] fn serialize(&self, s: &mut S) -> Result<(), E> { s.serialize_uint(*self as uint) - /* - match *self { - UNKNOWN => { try!(s.serialize_EnumStart("Country", "UNKNOWN", 0))); } - A1 => { try!(s.serialize_EnumStart("Country", "A1", 0))); } - A2 => { try!(s.serialize_EnumStart("Country", "A2", 0))); } - O1 => { try!(s.serialize_EnumStart("Country", "O1", 0))); } - AD => { try!(s.serialize_EnumStart("Country", "AD", 0))); } - AE => { try!(s.serialize_EnumStart("Country", "AE", 0))); } - AF => { try!(s.serialize_EnumStart("Country", "AF", 0))); } - AG => { try!(s.serialize_EnumStart("Country", "AG", 0))); } - AI => { try!(s.serialize_EnumStart("Country", "AI", 0))); } - AL => { try!(s.serialize_EnumStart("Country", "AL", 0))); } - AM => { try!(s.serialize_EnumStart("Country", "AM", 0))); } - AO => { try!(s.serialize_EnumStart("Country", "AO", 0))); } - AP => { try!(s.serialize_EnumStart("Country", "AP", 0))); } - AQ => { try!(s.serialize_EnumStart("Country", "AQ", 0))); } - AR => { try!(s.serialize_EnumStart("Country", "AR", 0))); } - AS => { try!(s.serialize_EnumStart("Country", "AS", 0))); } - AT => { try!(s.serialize_EnumStart("Country", "AT", 0))); } - AU => { try!(s.serialize_EnumStart("Country", "AU", 0))); } - AW => { try!(s.serialize_EnumStart("Country", "AW", 0))); } - AX => { try!(s.serialize_EnumStart("Country", "AX", 0))); } - AZ => { try!(s.serialize_EnumStart("Country", "AZ", 0))); } - BA => { try!(s.serialize_EnumStart("Country", "BA", 0))); } - BB => { try!(s.serialize_EnumStart("Country", "BB", 0))); } - BD => { try!(s.serialize_EnumStart("Country", "BD", 0))); } - BE => { try!(s.serialize_EnumStart("Country", "BE", 0))); } - BF => { try!(s.serialize_EnumStart("Country", "BF", 0))); } - BG => { try!(s.serialize_EnumStart("Country", "BG", 0))); } - BH => { try!(s.serialize_EnumStart("Country", "BH", 0))); } - BI => { try!(s.serialize_EnumStart("Country", "BI", 0))); } - BJ => { try!(s.serialize_EnumStart("Country", "BJ", 0))); } - BL => { try!(s.serialize_EnumStart("Country", "BL", 0))); } - BM => { try!(s.serialize_EnumStart("Country", "BM", 0))); } - BN => { try!(s.serialize_EnumStart("Country", "BN", 0))); } - BO => { try!(s.serialize_EnumStart("Country", "BO", 0))); } - BQ => { try!(s.serialize_EnumStart("Country", "BQ", 0))); } - BR => { try!(s.serialize_EnumStart("Country", "BR", 0))); } - BS => { try!(s.serialize_EnumStart("Country", "BS", 0))); } - BT => { try!(s.serialize_EnumStart("Country", "BT", 0))); } - BV => { try!(s.serialize_EnumStart("Country", "BV", 0))); } - BW => { try!(s.serialize_EnumStart("Country", "BW", 0))); } - BY => { try!(s.serialize_EnumStart("Country", "BY", 0))); } - BZ => { try!(s.serialize_EnumStart("Country", "BZ", 0))); } - CA => { try!(s.serialize_EnumStart("Country", "CA", 0))); } - CC => { try!(s.serialize_EnumStart("Country", "CC", 0))); } - CD => { try!(s.serialize_EnumStart("Country", "CD", 0))); } - CF => { try!(s.serialize_EnumStart("Country", "CF", 0))); } - CG => { try!(s.serialize_EnumStart("Country", "CG", 0))); } - CH => { try!(s.serialize_EnumStart("Country", "CH", 0))); } - CI => { try!(s.serialize_EnumStart("Country", "CI", 0))); } - CK => { try!(s.serialize_EnumStart("Country", "CK", 0))); } - CL => { try!(s.serialize_EnumStart("Country", "CL", 0))); } - CM => { try!(s.serialize_EnumStart("Country", "CM", 0))); } - CN => { try!(s.serialize_EnumStart("Country", "CN", 0))); } - CO => { try!(s.serialize_EnumStart("Country", "CO", 0))); } - CR => { try!(s.serialize_EnumStart("Country", "CR", 0))); } - CU => { try!(s.serialize_EnumStart("Country", "CU", 0))); } - CV => { try!(s.serialize_EnumStart("Country", "CV", 0))); } - CW => { try!(s.serialize_EnumStart("Country", "CW", 0))); } - CX => { try!(s.serialize_EnumStart("Country", "CX", 0))); } - CY => { try!(s.serialize_EnumStart("Country", "CY", 0))); } - CZ => { try!(s.serialize_EnumStart("Country", "CZ", 0))); } - DE => { try!(s.serialize_EnumStart("Country", "DE", 0))); } - DJ => { try!(s.serialize_EnumStart("Country", "DJ", 0))); } - DK => { try!(s.serialize_EnumStart("Country", "DK", 0))); } - DM => { try!(s.serialize_EnumStart("Country", "DM", 0))); } - DO => { try!(s.serialize_EnumStart("Country", "DO", 0))); } - DZ => { try!(s.serialize_EnumStart("Country", "DZ", 0))); } - EC => { try!(s.serialize_EnumStart("Country", "EC", 0))); } - EE => { try!(s.serialize_EnumStart("Country", "EE", 0))); } - EG => { try!(s.serialize_EnumStart("Country", "EG", 0))); } - EH => { try!(s.serialize_EnumStart("Country", "EH", 0))); } - ER => { try!(s.serialize_EnumStart("Country", "ER", 0))); } - ES => { try!(s.serialize_EnumStart("Country", "ES", 0))); } - ET => { try!(s.serialize_EnumStart("Country", "ET", 0))); } - EU => { try!(s.serialize_EnumStart("Country", "EU", 0))); } - FI => { try!(s.serialize_EnumStart("Country", "FI", 0))); } - FJ => { try!(s.serialize_EnumStart("Country", "FJ", 0))); } - FK => { try!(s.serialize_EnumStart("Country", "FK", 0))); } - FM => { try!(s.serialize_EnumStart("Country", "FM", 0))); } - FO => { try!(s.serialize_EnumStart("Country", "FO", 0))); } - FR => { try!(s.serialize_EnumStart("Country", "FR", 0))); } - GA => { try!(s.serialize_EnumStart("Country", "GA", 0))); } - GB => { try!(s.serialize_EnumStart("Country", "GB", 0))); } - GD => { try!(s.serialize_EnumStart("Country", "GD", 0))); } - GE => { try!(s.serialize_EnumStart("Country", "GE", 0))); } - GF => { try!(s.serialize_EnumStart("Country", "GF", 0))); } - GG => { try!(s.serialize_EnumStart("Country", "GG", 0))); } - GH => { try!(s.serialize_EnumStart("Country", "GH", 0))); } - GI => { try!(s.serialize_EnumStart("Country", "GI", 0))); } - GL => { try!(s.serialize_EnumStart("Country", "GL", 0))); } - GM => { try!(s.serialize_EnumStart("Country", "GM", 0))); } - GN => { try!(s.serialize_EnumStart("Country", "GN", 0))); } - GP => { try!(s.serialize_EnumStart("Country", "GP", 0))); } - GQ => { try!(s.serialize_EnumStart("Country", "GQ", 0))); } - GR => { try!(s.serialize_EnumStart("Country", "GR", 0))); } - GS => { try!(s.serialize_EnumStart("Country", "GS", 0))); } - GT => { try!(s.serialize_EnumStart("Country", "GT", 0))); } - GU => { try!(s.serialize_EnumStart("Country", "GU", 0))); } - GW => { try!(s.serialize_EnumStart("Country", "GW", 0))); } - GY => { try!(s.serialize_EnumStart("Country", "GY", 0))); } - HK => { try!(s.serialize_EnumStart("Country", "HK", 0))); } - HM => { try!(s.serialize_EnumStart("Country", "HM", 0))); } - HN => { try!(s.serialize_EnumStart("Country", "HN", 0))); } - HR => { try!(s.serialize_EnumStart("Country", "HR", 0))); } - HT => { try!(s.serialize_EnumStart("Country", "HT", 0))); } - HU => { try!(s.serialize_EnumStart("Country", "HU", 0))); } - ID => { try!(s.serialize_EnumStart("Country", "ID", 0))); } - IE => { try!(s.serialize_EnumStart("Country", "IE", 0))); } - IL => { try!(s.serialize_EnumStart("Country", "IL", 0))); } - IM => { try!(s.serialize_EnumStart("Country", "IM", 0))); } - IN => { try!(s.serialize_EnumStart("Country", "IN", 0))); } - IO => { try!(s.serialize_EnumStart("Country", "IO", 0))); } - IQ => { try!(s.serialize_EnumStart("Country", "IQ", 0))); } - IR => { try!(s.serialize_EnumStart("Country", "IR", 0))); } - IS => { try!(s.serialize_EnumStart("Country", "IS", 0))); } - IT => { try!(s.serialize_EnumStart("Country", "IT", 0))); } - JE => { try!(s.serialize_EnumStart("Country", "JE", 0))); } - JM => { try!(s.serialize_EnumStart("Country", "JM", 0))); } - JO => { try!(s.serialize_EnumStart("Country", "JO", 0))); } - JP => { try!(s.serialize_EnumStart("Country", "JP", 0))); } - KE => { try!(s.serialize_EnumStart("Country", "KE", 0))); } - KG => { try!(s.serialize_EnumStart("Country", "KG", 0))); } - KH => { try!(s.serialize_EnumStart("Country", "KH", 0))); } - KI => { try!(s.serialize_EnumStart("Country", "KI", 0))); } - KM => { try!(s.serialize_EnumStart("Country", "KM", 0))); } - KN => { try!(s.serialize_EnumStart("Country", "KN", 0))); } - KP => { try!(s.serialize_EnumStart("Country", "KP", 0))); } - KR => { try!(s.serialize_EnumStart("Country", "KR", 0))); } - KW => { try!(s.serialize_EnumStart("Country", "KW", 0))); } - KY => { try!(s.serialize_EnumStart("Country", "KY", 0))); } - KZ => { try!(s.serialize_EnumStart("Country", "KZ", 0))); } - LA => { try!(s.serialize_EnumStart("Country", "LA", 0))); } - LB => { try!(s.serialize_EnumStart("Country", "LB", 0))); } - LC => { try!(s.serialize_EnumStart("Country", "LC", 0))); } - LI => { try!(s.serialize_EnumStart("Country", "LI", 0))); } - LK => { try!(s.serialize_EnumStart("Country", "LK", 0))); } - LR => { try!(s.serialize_EnumStart("Country", "LR", 0))); } - LS => { try!(s.serialize_EnumStart("Country", "LS", 0))); } - LT => { try!(s.serialize_EnumStart("Country", "LT", 0))); } - LU => { try!(s.serialize_EnumStart("Country", "LU", 0))); } - LV => { try!(s.serialize_EnumStart("Country", "LV", 0))); } - LY => { try!(s.serialize_EnumStart("Country", "LY", 0))); } - MA => { try!(s.serialize_EnumStart("Country", "MA", 0))); } - MC => { try!(s.serialize_EnumStart("Country", "MC", 0))); } - MD => { try!(s.serialize_EnumStart("Country", "MD", 0))); } - ME => { try!(s.serialize_EnumStart("Country", "ME", 0))); } - MF => { try!(s.serialize_EnumStart("Country", "MF", 0))); } - MG => { try!(s.serialize_EnumStart("Country", "MG", 0))); } - MH => { try!(s.serialize_EnumStart("Country", "MH", 0))); } - MK => { try!(s.serialize_EnumStart("Country", "MK", 0))); } - ML => { try!(s.serialize_EnumStart("Country", "ML", 0))); } - MM => { try!(s.serialize_EnumStart("Country", "MM", 0))); } - MN => { try!(s.serialize_EnumStart("Country", "MN", 0))); } - MO => { try!(s.serialize_EnumStart("Country", "MO", 0))); } - MP => { try!(s.serialize_EnumStart("Country", "MP", 0))); } - MQ => { try!(s.serialize_EnumStart("Country", "MQ", 0))); } - MR => { try!(s.serialize_EnumStart("Country", "MR", 0))); } - MS => { try!(s.serialize_EnumStart("Country", "MS", 0))); } - MT => { try!(s.serialize_EnumStart("Country", "MT", 0))); } - MU => { try!(s.serialize_EnumStart("Country", "MU", 0))); } - MV => { try!(s.serialize_EnumStart("Country", "MV", 0))); } - MW => { try!(s.serialize_EnumStart("Country", "MW", 0))); } - MX => { try!(s.serialize_EnumStart("Country", "MX", 0))); } - MY => { try!(s.serialize_EnumStart("Country", "MY", 0))); } - MZ => { try!(s.serialize_EnumStart("Country", "MZ", 0))); } - NA => { try!(s.serialize_EnumStart("Country", "NA", 0))); } - NC => { try!(s.serialize_EnumStart("Country", "NC", 0))); } - NE => { try!(s.serialize_EnumStart("Country", "NE", 0))); } - NF => { try!(s.serialize_EnumStart("Country", "NF", 0))); } - NG => { try!(s.serialize_EnumStart("Country", "NG", 0))); } - NI => { try!(s.serialize_EnumStart("Country", "NI", 0))); } - NL => { try!(s.serialize_EnumStart("Country", "NL", 0))); } - NO => { try!(s.serialize_EnumStart("Country", "NO", 0))); } - NP => { try!(s.serialize_EnumStart("Country", "NP", 0))); } - NR => { try!(s.serialize_EnumStart("Country", "NR", 0))); } - NU => { try!(s.serialize_EnumStart("Country", "NU", 0))); } - NZ => { try!(s.serialize_EnumStart("Country", "NZ", 0))); } - OM => { try!(s.serialize_EnumStart("Country", "OM", 0))); } - PA => { try!(s.serialize_EnumStart("Country", "PA", 0))); } - PE => { try!(s.serialize_EnumStart("Country", "PE", 0))); } - PF => { try!(s.serialize_EnumStart("Country", "PF", 0))); } - PG => { try!(s.serialize_EnumStart("Country", "PG", 0))); } - PH => { try!(s.serialize_EnumStart("Country", "PH", 0))); } - PK => { try!(s.serialize_EnumStart("Country", "PK", 0))); } - PL => { try!(s.serialize_EnumStart("Country", "PL", 0))); } - PM => { try!(s.serialize_EnumStart("Country", "PM", 0))); } - PN => { try!(s.serialize_EnumStart("Country", "PN", 0))); } - PR => { try!(s.serialize_EnumStart("Country", "PR", 0))); } - PS => { try!(s.serialize_EnumStart("Country", "PS", 0))); } - PT => { try!(s.serialize_EnumStart("Country", "PT", 0))); } - PW => { try!(s.serialize_EnumStart("Country", "PW", 0))); } - PY => { try!(s.serialize_EnumStart("Country", "PY", 0))); } - QA => { try!(s.serialize_EnumStart("Country", "QA", 0))); } - RE => { try!(s.serialize_EnumStart("Country", "RE", 0))); } - RO => { try!(s.serialize_EnumStart("Country", "RO", 0))); } - RS => { try!(s.serialize_EnumStart("Country", "RS", 0))); } - RU => { try!(s.serialize_EnumStart("Country", "RU", 0))); } - RW => { try!(s.serialize_EnumStart("Country", "RW", 0))); } - SA => { try!(s.serialize_EnumStart("Country", "SA", 0))); } - SB => { try!(s.serialize_EnumStart("Country", "SB", 0))); } - SC => { try!(s.serialize_EnumStart("Country", "SC", 0))); } - SD => { try!(s.serialize_EnumStart("Country", "SD", 0))); } - SE => { try!(s.serialize_EnumStart("Country", "SE", 0))); } - SG => { try!(s.serialize_EnumStart("Country", "SG", 0))); } - SH => { try!(s.serialize_EnumStart("Country", "SH", 0))); } - SI => { try!(s.serialize_EnumStart("Country", "SI", 0))); } - SJ => { try!(s.serialize_EnumStart("Country", "SJ", 0))); } - SK => { try!(s.serialize_EnumStart("Country", "SK", 0))); } - SL => { try!(s.serialize_EnumStart("Country", "SL", 0))); } - SM => { try!(s.serialize_EnumStart("Country", "SM", 0))); } - SN => { try!(s.serialize_EnumStart("Country", "SN", 0))); } - SO => { try!(s.serialize_EnumStart("Country", "SO", 0))); } - SR => { try!(s.serialize_EnumStart("Country", "SR", 0))); } - SS => { try!(s.serialize_EnumStart("Country", "SS", 0))); } - ST => { try!(s.serialize_EnumStart("Country", "ST", 0))); } - SV => { try!(s.serialize_EnumStart("Country", "SV", 0))); } - SX => { try!(s.serialize_EnumStart("Country", "SX", 0))); } - SY => { try!(s.serialize_EnumStart("Country", "SY", 0))); } - SZ => { try!(s.serialize_EnumStart("Country", "SZ", 0))); } - TC => { try!(s.serialize_EnumStart("Country", "TC", 0))); } - TD => { try!(s.serialize_EnumStart("Country", "TD", 0))); } - TF => { try!(s.serialize_EnumStart("Country", "TF", 0))); } - TG => { try!(s.serialize_EnumStart("Country", "TG", 0))); } - TH => { try!(s.serialize_EnumStart("Country", "TH", 0))); } - TJ => { try!(s.serialize_EnumStart("Country", "TJ", 0))); } - TK => { try!(s.serialize_EnumStart("Country", "TK", 0))); } - TL => { try!(s.serialize_EnumStart("Country", "TL", 0))); } - TM => { try!(s.serialize_EnumStart("Country", "TM", 0))); } - TN => { try!(s.serialize_EnumStart("Country", "TN", 0))); } - TO => { try!(s.serialize_EnumStart("Country", "TO", 0))); } - TR => { try!(s.serialize_EnumStart("Country", "TR", 0))); } - TT => { try!(s.serialize_EnumStart("Country", "TT", 0))); } - TV => { try!(s.serialize_EnumStart("Country", "TV", 0))); } - TW => { try!(s.serialize_EnumStart("Country", "TW", 0))); } - TZ => { try!(s.serialize_EnumStart("Country", "TZ", 0))); } - UA => { try!(s.serialize_EnumStart("Country", "UA", 0))); } - UG => { try!(s.serialize_EnumStart("Country", "UG", 0))); } - UM => { try!(s.serialize_EnumStart("Country", "UM", 0))); } - US => { try!(s.serialize_EnumStart("Country", "US", 0))); } - UY => { try!(s.serialize_EnumStart("Country", "UY", 0))); } - UZ => { try!(s.serialize_EnumStart("Country", "UZ", 0))); } - VA => { try!(s.serialize_EnumStart("Country", "VA", 0))); } - VC => { try!(s.serialize_EnumStart("Country", "VC", 0))); } - VE => { try!(s.serialize_EnumStart("Country", "VE", 0))); } - VG => { try!(s.serialize_EnumStart("Country", "VG", 0))); } - VI => { try!(s.serialize_EnumStart("Country", "VI", 0))); } - VN => { try!(s.serialize_EnumStart("Country", "VN", 0))); } - VU => { try!(s.serialize_EnumStart("Country", "VU", 0))); } - WF => { try!(s.serialize_EnumStart("Country", "WF", 0))); } - WS => { try!(s.serialize_EnumStart("Country", "WS", 0))); } - XX => { try!(s.serialize_EnumStart("Country", "XX", 0))); } - YE => { try!(s.serialize_EnumStart("Country", "YE", 0))); } - YT => { try!(s.serialize_EnumStart("Country", "YT", 0))); } - ZA => { try!(s.serialize_EnumStart("Country", "ZA", 0))); } - ZM => { try!(s.serialize_EnumStart("Country", "ZM", 0))); } - ZW => { try!(s.serialize_EnumStart("Country", "ZW", 0))); } - } - - s.serialize_end() - */ } } @@ -907,7 +536,6 @@ impl Log { fn bench_encoder(b: &mut Bencher) { let log = Log::new(); let json = serialize::json::Encoder::str_encode(&log); - //println!("json: {}", json); let _len = json.len(); b.iter(|| { @@ -925,7 +553,6 @@ fn bench_serializer(b: &mut Bencher) { log.serialize(&mut serializer).unwrap(); } let json = String::from_utf8(wr.unwrap()).unwrap(); - //println!("json: {}", json); let _len = json.len(); b.iter(|| { @@ -934,20 +561,16 @@ fn bench_serializer(b: &mut Bencher) { let mut serializer = json::Serializer::new(&mut wr); log.serialize(&mut serializer).unwrap(); } - //let _ = String::from_utf8(wr.unwrap()); + let _ = String::from_utf8(wr.unwrap()); }); } #[bench] -fn bench_decooder(b: &mut Bencher) { +fn bench_decoder(b: &mut Bencher) { let s = r#"{"timestamp":2837513946597,"zone_id":123456,"zone_plan":"FREE","http":{"protocol":"HTTP11","status":200,"host_status":503,"up_status":520,"method":"GET","content_type":"text/html","user_agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36","referer":"https://www.cloudflare.com/","request_uri":"/cdn-cgi/trace"},"origin":{"ip":"1.2.3.4","port":8000,"hostname":"www.example.com","protocol":"HTTPS"},"country":"US","cache_status":"Hit","server_ip":"192.168.1.1","server_name":"metal.cloudflare.com","remote_ip":"10.1.2.3","bytes_dlv":123456,"ray_id":"10c73629cce30078-LAX"}"#; - - - //"{"timestamp":3444218605346,"zone_id":123456,"zone_plan":1,"http":{"protocol":2,"status":200,"host_status":503,"up_status":520,"method":1,"content_type":"text/html","user_agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36","referer":"https://www.cloudflare.com/","request_uri":"/cdn-cgi/trace"},"origin":{"ip":"1.2.3.4","port":8000,"hostname":"www.example.com","protocol":2},"country":238,"cache_status":3,"server_ip":"192.168.1.1","server_name":"metal.cloudflare.com","remote_ip":"10.1.2.3","bytes_dlv":123456,"ray_id":"10c73629cce30078-LAX"}"#; b.iter(|| { let json = serialize::json::from_str(s).unwrap(); - //println!("json: {}", json); let mut decoder = serialize::json::Decoder::new(json); let _log: Log = serialize::Decodable::decode(&mut decoder).unwrap(); }); diff --git a/json.rs b/json.rs index c842a251..0a30da3d 100644 --- a/json.rs +++ b/json.rs @@ -230,7 +230,6 @@ fn main() { use std::char; use std::collections::{HashMap, TreeMap}; use std::collections::treemap; -use std::f64; use std::fmt; use std::io::MemWriter; use std::io; @@ -267,7 +266,6 @@ impl Json { self.serialize(&mut serializer) } - /* /// Encodes a json value into an io::writer. /// Pretty-prints in a more readable format. pub fn to_pretty_writer(&self, wr: &mut Writer) -> EncodeResult { @@ -281,7 +279,6 @@ impl Json { self.to_pretty_writer(&mut s as &mut Writer).unwrap(); str::from_utf8(s.unwrap().as_slice()).unwrap().to_string() } - */ /// If the Json value is an Object, returns the value associated with the provided key. /// Otherwise, returns None. @@ -415,6 +412,13 @@ impl Json { } } +impl fmt::Show for Json { + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.to_writer(f).map_err(|_| fmt::WriteError) + } +} + impl, E> ser::Serializable for Json { #[inline] fn serialize(&self, s: &mut S) -> Result<(), E> { @@ -724,30 +728,28 @@ fn io_error_to_error(io: io::IoError) -> ParserError { pub type EncodeResult = io::IoResult<()>; -fn escape_str(s: &str) -> String { - let mut escaped = String::from_str("\""); - for c in s.chars() { - match c { - '"' => escaped.push_str("\\\""), - '\\' => escaped.push_str("\\\\"), - '\x08' => escaped.push_str("\\b"), - '\x0c' => escaped.push_str("\\f"), - '\n' => escaped.push_str("\\n"), - '\r' => escaped.push_str("\\r"), - '\t' => escaped.push_str("\\t"), - _ => escaped.push_char(c), +fn escape_str(wr: &mut Writer, s: &str) -> Result<(), io::IoError> { + try!(wr.write_str("\"")); + for byte in s.bytes() { + match byte { + b'"' => try!(wr.write_str("\\\"")), + b'\\' => try!(wr.write_str("\\\\")), + b'\x08' => try!(wr.write_str("\\b")), + b'\x0c' => try!(wr.write_str("\\f")), + b'\n' => try!(wr.write_str("\\n")), + b'\r' => try!(wr.write_str("\\r")), + b'\t' => try!(wr.write_str("\\t")), + _ => try!(wr.write_u8(byte)), } - }; - escaped.push_char('"'); - escaped + } + wr.write_str("\"") } -fn spaces(n: uint) -> String { - let mut ss = String::new(); +fn spaces(wr: &mut Writer, n: uint) -> Result<(), io::IoError> { for _ in range(0, n) { - ss.push_str(" "); + try!(wr.write_str(" ")); } - return ss + Ok(()) } #[deriving(Show)] @@ -798,73 +800,20 @@ impl<'a> Serializer<'a> { let buf = Serializer::buf_encode(value); String::from_utf8(buf) } - - /* - fn serialize_seq<'a>(&mut self, token: ser::Token<'a>, first: bool) -> Result<(), io::IoError> { - match token { - ser::End => { - write!(self.wr, "]") - } - token => { - self.state_stack.push(SeqState(false)); - - if !first { - try!(write!(self.wr, ",")); - } - self.serialize_value(token) - } - } - } - - fn serialize_map<'a>(&mut self, token: ser::Token<'a>, first: bool) -> Result<(), io::IoError> { - match token { - ser::End => { - write!(self.wr, "}}") - } - ser::Str(v) => { - self.state_stack.push(MapState(false)); - self.state_stack.push(ValueState); - - if !first { - try!(write!(self.wr, ",")); - } - - write!(self.wr, "{}:", escape_str(v)) - } - _token => fail!() - } - } - - fn serialize_enum<'a>(&mut self, token: ser::Token<'a>, first: bool) -> Result<(), io::IoError> { - match token { - ser::End => { - write!(self.wr, "]}}") - } - _ => { - self.state_stack.push(EnumState(false)); - - if !first { - try!(write!(self.wr, ",")); - } - self.serialize_value(token) - } - } - } - */ } impl<'a> ser::Serializer for Serializer<'a> { #[inline] fn serialize_null(&mut self) -> Result<(), io::IoError> { - write!(self.wr, "null") + self.wr.write_str("null") } #[inline] fn serialize_bool(&mut self, v: bool) -> Result<(), io::IoError> { if v { - write!(self.wr, "true") + self.wr.write_str("true") } else { - write!(self.wr, "false") + self.wr.write_str("false") } } @@ -925,24 +874,23 @@ impl<'a> ser::Serializer for Serializer<'a> { #[inline] fn serialize_f64(&mut self, v: f64) -> Result<(), io::IoError> { - write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) + write!(self.wr, "{}", v) } #[inline] fn serialize_char(&mut self, v: char) -> Result<(), io::IoError> { - write!(self.wr, "{}", escape_str(str::from_char(v).as_slice())) + escape_str(self.wr, str::from_char(v).as_slice()) } #[inline] fn serialize_str(&mut self, v: &str) -> Result<(), io::IoError> { - write!(self.wr, "{}", escape_str(v)) + escape_str(self.wr, v) } #[inline] fn serialize_tuple_start(&mut self, _len: uint) -> Result<(), io::IoError> { - //self.state_stack.push(TupleState); self.first = true; - write!(self.wr, "[") + self.wr.write_str("[") } #[inline] @@ -951,19 +899,19 @@ impl<'a> ser::Serializer for Serializer<'a> { self.first = false; Ok(()) } else { - write!(self.wr, ",") + self.wr.write_str(",") } } #[inline] fn serialize_tuple_end(&mut self) -> Result<(), io::IoError> { - write!(self.wr, "]") + self.wr.write_str("]") } #[inline] fn serialize_struct_start(&mut self, _name: &str, _len: uint) -> Result<(), io::IoError> { self.first = true; - write!(self.wr, "{{") + self.wr.write_str("{") } #[inline] @@ -971,21 +919,23 @@ impl<'a> ser::Serializer for Serializer<'a> { if self.first { self.first = false; } else { - try!(write!(self.wr, ",")); + try!(self.wr.write_str(",")); } try!(name.serialize(self)); - write!(self.wr, ":") + self.wr.write_str(":") } #[inline] fn serialize_struct_end(&mut self) -> Result<(), io::IoError> { - write!(self.wr, "}}") + self.wr.write_str("}") } #[inline] fn serialize_enum_start(&mut self, _name: &str, variant: &str, _len: uint) -> Result<(), io::IoError> { self.first = true; - write!(self.wr, "{{{}:[", escape_str(variant)) + try!(self.wr.write_str("{")); + try!(self.serialize_str(variant)); + self.wr.write_str(":[") } #[inline] @@ -994,49 +944,15 @@ impl<'a> ser::Serializer for Serializer<'a> { self.first = false; Ok(()) } else { - write!(self.wr, ",") + self.wr.write_str(",") } } #[inline] fn serialize_enum_end(&mut self) -> Result<(), io::IoError> { - write!(self.wr, "]}}") + self.wr.write_str("]}") } - /* - #[inline] - fn serialize_sep(&mut self) -> Result<(), io::IoError> { - match self.state_stack.last() { - Some(&TupleState) | Some(&StructState) | Some(&EnumState) => { - write!(self.wr, ",") - } - Some(&ValueState) | None => { - fail!() - //Err(SyntaxError) - } - } - } - - #[inline] - fn serialize_tuple_end(&mut self) -> Result<(), io::IoError> { - match self.state_stack.pop() { - Some(TupleState) => { - write!(self.wr, "]") - } - Some(StructState) => { - write!(self.wr, "}}") - } - Some(EnumState) => { - write!(self.wr, "]}}") - } - Some(ValueState) | None => { - fail!() - //Err(SyntaxError) - } - } - } - */ - #[inline] fn serialize_option< T: Serializable, io::IoError> @@ -1056,18 +972,18 @@ impl<'a> ser::Serializer for Serializer<'a> { T: Serializable, io::IoError>, Iter: Iterator >(&mut self, mut iter: Iter) -> Result<(), io::IoError> { - try!(write!(self.wr, "[")); + try!(self.wr.write_str("[")); let mut first = true; for elt in iter { if first { first = false; } else { - try!(write!(self.wr, ",")); + try!(self.wr.write_str(",")); } try!(elt.serialize(self)); } - write!(self.wr, "]") + self.wr.write_str("]") } #[inline] @@ -1076,30 +992,29 @@ impl<'a> ser::Serializer for Serializer<'a> { V: Serializable, io::IoError>, Iter: Iterator<(K, V)> >(&mut self, mut iter: Iter) -> Result<(), io::IoError> { - try!(write!(self.wr, "{{")); + try!(self.wr.write_str("{")); let mut first = true; for (key, value) in iter { if first { first = false; } else { - try!(write!(self.wr, ",")); + try!(self.wr.write_str(",")); } try!(key.serialize(self)); - try!(write!(self.wr, ":")); + try!(self.wr.write_str(":")); try!(value.serialize(self)); } - write!(self.wr, "}}") + self.wr.write_str("}") } } -/* /// Another serializer for JSON, but prints out human-readable JSON instead of /// compact data pub struct PrettySerializer<'a> { wr: &'a mut Writer, indent: uint, - state_stack: Vec, + first: bool, } impl<'a> PrettySerializer<'a> { @@ -1108,19 +1023,20 @@ impl<'a> PrettySerializer<'a> { PrettySerializer { wr: wr, indent: 0, - state_stack: vec!(ValueState), + first: true, } } - /* /// Encode the specified struct into a json [u8] pub fn buf_encode< T: ser::Serializable, io::IoError> >(value: &T) -> Vec { let mut wr = MemWriter::new(); - { + // FIXME(14302) remove the transmute and unsafe block. + unsafe { let mut serializer = PrettySerializer::new(&mut wr); - value.serialize(&mut serializer).unwrap(); + // MemWriter never Errs + let _ = value.serialize(transmute(&mut serializer)); } wr.unwrap() } @@ -1132,148 +1048,46 @@ impl<'a> PrettySerializer<'a> { let buf = PrettySerializer::buf_encode(value); String::from_utf8(buf) } - */ - /* - fn serialize_value<'a>(&mut self, token: ser::Token<'a>) -> Result<(), io::IoError> { - match token { - ser::Null => { write!(self.wr, "null") } - ser::Bool(true) => { write!(self.wr, "true") } - ser::Bool(false) => { write!(self.wr, "false") } - ser::Int(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::I8(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::I16(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::I32(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::I64(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::Uint(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::U8(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::U16(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::U32(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::U64(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::F32(v) => { write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) } - ser::F64(v) => { write!(self.wr, "{}", f64::to_str_digits(v, 6)) } - ser::Char(v) => { write!(self.wr, "{}", escape_str(str::from_char(v).as_slice())) } - ser::Str(v) => { write!(self.wr, "{}", escape_str(v)) } - ser::Option(false) => { write!(self.wr, "null") } - ser::Option(true) => { - self.state_stack.push(ValueState); - Ok(()) - } - ser::TupleStart(_) - | ser::SeqStart(_) => { - self.state_stack.push(SeqState(true)); - self.indent += 2; - write!(self.wr, "[") - } - ser::StructStart(_, _) - | ser::MapStart(_) => { - self.state_stack.push(MapState(true)); - self.indent += 2; - write!(self.wr, "{{") - } - ser::EnumStart(_, variant, _) => { - self.state_stack.push(EnumState(true)); - self.indent += 2; - try!(write!(self.wr, "{{\n{}{}: [", spaces(self.indent), escape_str(variant))); - self.indent += 2; - Ok(()) - } - ser::End => { fail!("not implemented") } + #[inline] + fn serialize_sep(&mut self) -> Result<(), io::IoError> { + if self.first { + self.first = false; + self.indent += 2; + try!(self.wr.write_str("\n")); + } else { + try!(self.wr.write_str(",\n")); } + + spaces(self.wr, self.indent) } - fn serialize_seq<'a>(&mut self, token: ser::Token<'a>, first: bool) -> Result<(), io::IoError> { - match token { - ser::End => { - self.indent -= 2; - if first { - write!(self.wr, "]") - } else { - write!(self.wr, "\n{}]", spaces(self.indent)) - } - } - token => { - self.state_stack.push(SeqState(false)); - - if first { - try!(write!(self.wr, "\n")); - } else { - try!(write!(self.wr, ",\n")); - } - - try!(write!(self.wr, "{}", spaces(self.indent))); - self.serialize_value(token) - } + #[inline] + fn serialize_end(&mut self, s: &str) -> Result<(), io::IoError> { + if !self.first { + try!(self.wr.write_str("\n")); + self.indent -= 2; + try!(spaces(self.wr, self.indent)); } + + self.first = false; + + self.wr.write_str(s) } - - fn serialize_map<'a>(&mut self, token: ser::Token<'a>, first: bool) -> Result<(), io::IoError> { - match token { - ser::End => { - self.indent -= 2; - if first { - write!(self.wr, "}}") - } else { - write!(self.wr, "\n{}}}", spaces(self.indent)) - } - } - ser::Str(v) => { - self.state_stack.push(MapState(false)); - self.state_stack.push(ValueState); - - if first { - try!(write!(self.wr, "\n")); - } else { - try!(write!(self.wr, ",\n")); - } - - write!(self.wr, "{}{}: ", spaces(self.indent), escape_str(v)) - } - token => fail!("bad token: {}", token) - } - } - - fn serialize_enum<'a>(&mut self, token: ser::Token<'a>, first: bool) -> Result<(), io::IoError> { - match token { - ser::End => { - self.indent -= 2; - if first { - try!(write!(self.wr, "]")); - } else { - try!(write!(self.wr, "\n{}]", spaces(self.indent))); - } - self.indent -= 2; - write!(self.wr, "\n{}}}", spaces(self.indent)) - } - _ => { - self.state_stack.push(EnumState(false)); - - if first { - try!(write!(self.wr, "\n")); - } else { - try!(write!(self.wr, ",\n")); - } - - try!(write!(self.wr, "{}", spaces(self.indent))); - self.serialize_value(token) - } - } - } - */ } impl<'a> ser::Serializer for PrettySerializer<'a> { #[inline] fn serialize_null(&mut self) -> Result<(), io::IoError> { - write!(self.wr, "null") + self.wr.write_str("null") } #[inline] fn serialize_bool(&mut self, v: bool) -> Result<(), io::IoError> { if v { - write!(self.wr, "true") + self.wr.write_str("true") } else { - write!(self.wr, "false") + self.wr.write_str("false") } } @@ -1334,67 +1148,69 @@ impl<'a> ser::Serializer for PrettySerializer<'a> { #[inline] fn serialize_f64(&mut self, v: f64) -> Result<(), io::IoError> { - write!(self.wr, "{}", f64::to_str_digits(v as f64, 6)) + write!(self.wr, "{}", v) } #[inline] fn serialize_char(&mut self, v: char) -> Result<(), io::IoError> { - write!(self.wr, "{}", escape_str(str::from_char(v).as_slice())) + escape_str(self.wr, str::from_char(v).as_slice()) } #[inline] fn serialize_str(&mut self, v: &str) -> Result<(), io::IoError> { - write!(self.wr, "{}", escape_str(v)) + escape_str(self.wr, v) } #[inline] fn serialize_tuple_start(&mut self, _len: uint) -> Result<(), io::IoError> { - self.state_stack.push(TupleState); - write!(self.wr, "[") + self.first = true; + self.wr.write_str("[") + } + + #[inline] + fn serialize_tuple_sep(&mut self) -> Result<(), io::IoError> { + self.serialize_sep() + } + + #[inline] + fn serialize_tuple_end(&mut self) -> Result<(), io::IoError> { + self.serialize_end("]") } #[inline] fn serialize_struct_start(&mut self, _name: &str, _len: uint) -> Result<(), io::IoError> { - self.state_stack.push(StructState); - write!(self.wr, "{{") + self.first = true; + self.wr.write_str("{") } #[inline] - fn serialize_enum_start(&mut self, _name: &str, variant: &str, _len: uint) -> Result<(), io::IoError> { - self.state_stack.push(EnumState); - write!(self.wr, "{{{}:[", escape_str(variant)) + fn serialize_struct_sep(&mut self, name: &str) -> Result<(), io::IoError> { + try!(self.serialize_sep()); + try!(self.serialize_str(name)); + self.wr.write_str(": ") } #[inline] - fn serialize_sep(&mut self) -> Result<(), io::IoError> { - match self.state_stack.last() { - Some(&TupleState) | Some(&StructState) | Some(&EnumState) => { - write!(self.wr, ",") - } - Some(&ValueState) | None => { - fail!() - //Err(SyntaxError) - } - } + fn serialize_struct_end(&mut self) -> Result<(), io::IoError> { + self.serialize_end("}") } #[inline] - fn serialize_end(&mut self) -> Result<(), io::IoError> { - match self.state_stack.pop() { - Some(TupleState) => { - write!(self.wr, "]") - } - Some(StructState) => { - write!(self.wr, "}}") - } - Some(EnumState) => { - write!(self.wr, "]}}") - } - Some(ValueState) | None => { - fail!() - //Err(SyntaxError) - } - } + fn serialize_enum_start(&mut self, _name: &str, variant: &str, len: uint) -> Result<(), io::IoError> { + try!(self.serialize_struct_start("", 1)); + try!(self.serialize_struct_sep(variant)); + self.serialize_tuple_start(len) + } + + #[inline] + fn serialize_enum_sep(&mut self) -> Result<(), io::IoError> { + self.serialize_tuple_sep() + } + + #[inline] + fn serialize_enum_end(&mut self) -> Result<(), io::IoError> { + try!(self.serialize_tuple_end()); + self.serialize_struct_end() } #[inline] @@ -1416,18 +1232,15 @@ impl<'a> ser::Serializer for PrettySerializer<'a> { T: Serializable, io::IoError>, Iter: Iterator >(&mut self, mut iter: Iter) -> Result<(), io::IoError> { - try!(write!(self.wr, "[")); - let mut first = true; - for elt in iter { - if first { - first = false; - } else { - try!(write!(self.wr, ",")); - } - try!(elt.serialize(self)); + try!(self.wr.write_str("[")); + self.first = true; + for elt in iter { + try!(self.serialize_sep()); + try!(elt.serialize(self)); } - write!(self.wr, "]") + + self.serialize_end("]") } #[inline] @@ -1436,23 +1249,19 @@ impl<'a> ser::Serializer for PrettySerializer<'a> { V: Serializable, io::IoError>, Iter: Iterator<(K, V)> >(&mut self, mut iter: Iter) -> Result<(), io::IoError> { - try!(write!(self.wr, "{{")); - let mut first = true; - for (key, value) in iter { - if first { - first = false; - } else { - try!(write!(self.wr, ",")); - } - try!(key.serialize(self)); - try!(write!(self.wr, ":")); - try!(value.serialize(self)); + try!(self.wr.write_str("{")); + self.first = true; + for (key, value) in iter { + try!(self.serialize_sep()); + try!(key.serialize(self)); + try!(self.wr.write_str(": ")); + try!(value.serialize(self)); } - write!(self.wr, "}}") + + self.serialize_end("}") } } -*/ /* /// The output of the streaming parser. @@ -2304,10 +2113,6 @@ impl ToJson for f64 { fn to_json(&self) -> Json { Number(*self) } } -impl ToJson for () { - fn to_json(&self) -> Json { Null } -} - impl ToJson for bool { fn to_json(&self) -> Json { Boolean(*self) } } @@ -2320,25 +2125,43 @@ impl ToJson for String { fn to_json(&self) -> Json { String((*self).clone()) } } -impl ToJson for (A, B) { - fn to_json(&self) -> Json { - match *self { - (ref a, ref b) => { - List(vec![a.to_json(), b.to_json()]) - } +macro_rules! peel_to_json_tuple { + ($name:ident, $($other:ident,)*) => (impl_to_json_tuple!($($other,)*)) +} + +macro_rules! impl_to_json_tuple { + () => { + impl<> ToJson for () { + #[inline] + fn to_json(&self) -> Json { + Null + } } + }; + ( $($name:ident,)+ ) => { + impl<$($name: ToJson),*> ToJson for ($($name,)*) { + #[inline] + #[allow(uppercase_variables)] + fn to_json(&self) -> Json { + // FIXME: how can we count macro args? + let mut len = 0; + $({ let $name = 1; len += $name; })*; + + let ($(ref $name,)*) = *self; + + let mut list = Vec::with_capacity(len); + $( + list.push($name.to_json()); + )* + + List(list) + } + } + peel_to_json_tuple!($($name,)*) } } -impl ToJson for (A, B, C) { - fn to_json(&self) -> Json { - match *self { - (ref a, ref b, ref c) => { - List(vec![a.to_json(), b.to_json(), c.to_json()]) - } - } - } -} +impl_to_json_tuple! { T0, T1, } // T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } impl ToJson for Vec { fn to_json(&self) -> Json { List(self.iter().map(|elt| elt.to_json()).collect()) } @@ -2373,14 +2196,6 @@ impl ToJson for Option { } } -impl fmt::Show for Json { - /// Encodes a json value into a string - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.to_writer(f).map_err(|_| fmt::WriteError) - } -} - -/* #[cfg(test)] mod tests { use std::io; @@ -2419,7 +2234,7 @@ mod tests { #[deriving(PartialEq, Show)] enum Animal { Dog, - Frog(String, int) + Frog(String, Vec) } impl, E> ser::Serializable for Animal { @@ -2428,13 +2243,18 @@ mod tests { match *self { Dog => { try!(s.serialize_enum_start("Animal", "Dog", 0)); - s.serialize_end() + s.serialize_enum_end() } - Frog(ref x0, x1) => { + Frog(ref x0, ref x1) => { try!(s.serialize_enum_start("Animal", "Frog", 2)); + + try!(s.serialize_enum_sep()); try!(x0.serialize(s)); + + try!(s.serialize_enum_sep()); try!(x1.serialize(s)); - s.serialize_end() + + s.serialize_enum_end() } } } @@ -2471,7 +2291,7 @@ mod tests { ) ) } - Frog(ref x0, x1) => { + Frog(ref x0, ref x1) => { Object( treemap!( "Frog".to_string() => List(vec!(x0.to_json(), x1.to_json())) @@ -2493,10 +2313,17 @@ mod tests { #[inline] fn serialize(&self, s: &mut S) -> Result<(), E> { try!(s.serialize_struct_start("Inner", 3)); + + try!(s.serialize_struct_sep("a")); try!(self.a.serialize(s)); + + try!(s.serialize_struct_sep("b")); try!(self.b.serialize(s)); + + try!(s.serialize_struct_sep("c")); try!(self.c.serialize(s)); - s.serialize_end() + + s.serialize_struct_end() } } @@ -2578,8 +2405,11 @@ mod tests { #[inline] fn serialize(&self, s: &mut S) -> Result<(), E> { try!(s.serialize_struct_start("Outer", 1)); + + try!(s.serialize_struct_sep("inner")); try!(self.inner.serialize(s)); - s.serialize_end() + + s.serialize_struct_end() } } @@ -2638,7 +2468,7 @@ mod tests { fn test_encode_ok< 'a, - T: PartialEq + Show + ToJson + ser::Serializable> + T: PartialEq + Show + ToJson + ser::Serializable, io::IoError> >(errors: &[(T, &str)]) { for &(ref value, out) in errors.iter() { let out = out.to_string(); @@ -2653,7 +2483,7 @@ mod tests { fn test_pretty_encode_ok< 'a, - T: PartialEq + Show + ToJson + ser::Serializable> + T: PartialEq + Show + ToJson + ser::Serializable, io::IoError> >(errors: &[(T, &str)]) { for &(ref value, out) in errors.iter() { let out = out.to_string(); @@ -2842,11 +2672,56 @@ mod tests { ]); } + #[test] + fn test_write_tuple() { + test_encode_ok([ + ( + (5,), + "[5]", + ), + ]); + + test_pretty_encode_ok([ + ( + (5,), + concat!( + "[\n", + " 5\n", + "]" + ), + ), + ]); + + test_encode_ok([ + ( + (5, (6, "abc")), + "[5,[6,\"abc\"]]", + ), + ]); + + test_pretty_encode_ok([ + ( + (5, (6, "abc")), + concat!( + "[\n", + " 5,\n", + " [\n", + " 6,\n", + " \"abc\"\n", + " ]\n", + "]" + ), + ), + ]); + } + #[test] fn test_write_enum() { test_encode_ok([ (Dog, "{\"Dog\":[]}"), - (Frog("Henry".to_string(), 349), "{\"Frog\":[\"Henry\",349]}"), + (Frog("Henry".to_string(), vec!()), "{\"Frog\":[\"Henry\",[]]}"), + (Frog("Henry".to_string(), vec!(349)), "{\"Frog\":[\"Henry\",[349]]}"), + (Frog("Henry".to_string(), vec!(349, 102)), "{\"Frog\":[\"Henry\",[349,102]]}"), ]); test_pretty_encode_ok([ @@ -2859,12 +2734,39 @@ mod tests { ), ), ( - Frog("Henry".to_string(), 349), + Frog("Henry".to_string(), vec!()), concat!( "{\n", " \"Frog\": [\n", " \"Henry\",\n", - " 349\n", + " []\n", + " ]\n", + "}" + ), + ), + ( + Frog("Henry".to_string(), vec!(349)), + concat!( + "{\n", + " \"Frog\": [\n", + " \"Henry\",\n", + " [\n", + " 349\n", + " ]\n", + " ]\n", + "}" + ), + ), + ( + Frog("Henry".to_string(), vec!(349, 102)), + concat!( + "{\n", + " \"Frog\": [\n", + " \"Henry\",\n", + " [\n", + " 349,\n", + " 102\n", + " ]\n", " ]\n", "}" ), @@ -3229,17 +3131,30 @@ mod tests { test_parse_ok([ ("{\"Dog\": []}", Dog), ( - "{\"Frog\": [\"Henry\", 349]}", - Frog("Henry".to_string(), 349), + "{\"Frog\": [\"Henry\", []]}", + Frog("Henry".to_string(), vec!()), + ), + ( + "{\"Frog\": [\"Henry\", [349]]}", + Frog("Henry".to_string(), vec!(349)), + ), + ( + "{\"Frog\": [\"Henry\", [349, 102]]}", + Frog("Henry".to_string(), vec!(349, 102)), ), ]); test_parse_ok([ ( - "{\"a\": {\"Dog\": []}, \"b\": {\"Frog\":[\"Henry\", 349]}}", + concat!( + "{", + " \"a\": {\"Dog\": []},", + " \"b\": {\"Frog\":[\"Henry\", []]}", + "}" + ), treemap!( "a".to_string() => Dog, - "b".to_string() => Frog("Henry".to_string(), 349) + "b".to_string() => Frog("Henry".to_string(), vec!()) ) ), ]); @@ -3249,7 +3164,9 @@ mod tests { fn test_json_deserialize_enum() { test_json_deserialize_ok([ Dog, - Frog("Henry".to_string(), 349), + Frog("Henry".to_string(), vec!()), + Frog("Henry".to_string(), vec!(349)), + Frog("Henry".to_string(), vec!(349, 102)), ]); } @@ -4062,4 +3979,3 @@ mod bench { bench_deserializer_streaming(b, 500) } } -*/ diff --git a/ser.rs b/ser.rs index b4834a7e..a24f02e2 100644 --- a/ser.rs +++ b/ser.rs @@ -237,7 +237,10 @@ macro_rules! impl_serialize_tuple { let ($(ref $name,)*) = *self; try!(s.serialize_tuple_start(len)); - $(try!($name.serialize(s));)* + $( + try!(s.serialize_tuple_sep()); + try!($name.serialize(s)); + )* s.serialize_tuple_end() } } @@ -299,7 +302,7 @@ mod tests { try!(s.serialize_struct_sep("inner")); try!(self.inner.serialize(s)); - s.serialize_enum_end() + s.serialize_struct_end() } } @@ -680,7 +683,7 @@ mod tests { Char('c'), MapEnd, StructEnd, - StructEnd, + SeqEnd, StructEnd, );