From d42062ce48ba3c502d51aff99017b4c1a4d9b5d7 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Mon, 24 Jul 2023 12:37:30 +0200 Subject: [PATCH] reformat code again --- examples/simple.rs | 2 +- src/error.rs | 2 - src/imf/address.rs | 91 ++++++++++++++++++++++----------------- src/imf/field.rs | 2 +- src/imf/identification.rs | 13 ++++-- src/imf/mailbox.rs | 10 +++-- src/imf/mod.rs | 43 +++++++++--------- src/lib.rs | 2 +- src/mime/field.rs | 2 +- src/mime/mime.rs | 2 +- src/mime/type.rs | 16 +++---- src/part/composite.rs | 47 ++++++++++++++------ src/part/discrete.rs | 24 ++++++----- src/part/field.rs | 10 +---- src/part/mod.rs | 33 ++++++++++---- src/text/boundary.rs | 8 +++- src/text/encoding.rs | 4 +- src/text/misc_token.rs | 14 ++++-- 18 files changed, 194 insertions(+), 131 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 0cd76a7..ebdca15 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -11,7 +11,7 @@ between the header information and the body of the message."#; let email = eml_codec::email(input).unwrap(); println!( - "{} just sent you an email with subject \"{}\"", + "{} just sent you an email with subject \"{}\"", email.imf.from[0].to_string(), email.imf.subject.unwrap().to_string(), ); diff --git a/src/error.rs b/src/error.rs index 21f9f03..4ac3c86 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,3 @@ - - #[derive(Debug, PartialEq)] pub enum EMLError<'a> { ParseError(nom::Err>), diff --git a/src/imf/address.rs b/src/imf/address.rs index 9c18c96..9b47bf7 100644 --- a/src/imf/address.rs +++ b/src/imf/address.rs @@ -176,8 +176,8 @@ mod tests { ); } + use crate::text::encoding::{EncodedWord, QuotedChunk, QuotedWord}; use crate::text::quoted::QuotedString; - use crate::text::encoding::{EncodedWord, QuotedWord, QuotedChunk}; #[test] fn test_strange_groups() { @@ -186,50 +186,61 @@ mod tests { br#""Colleagues": "James Smythe" ;, Friends: jane@example.com, =?UTF-8?Q?John_Sm=C3=AEth?= ;"# ), - Ok((&b""[..], vec![ - AddressRef::Many(GroupRef { - name: Phrase(vec![Word::Quoted(QuotedString(vec![&b"Colleagues"[..]]))]), - participants: vec![ - MailboxRef { + Ok(( + &b""[..], + vec![ + AddressRef::Many(GroupRef { + name: Phrase(vec![Word::Quoted(QuotedString(vec![&b"Colleagues"[..]]))]), + participants: vec![MailboxRef { name: Some(Phrase(vec![Word::Quoted(QuotedString(vec![ - &b"James"[..], &b" "[..], &b"Smythe"[..] + &b"James"[..], + &b" "[..], + &b"Smythe"[..] ]))])), addrspec: AddrSpec { - local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom(&b"james"[..]))]), + local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom( + &b"james"[..] + ))]), domain: Domain::Atoms(vec![&b"vandelay"[..], &b"com"[..]]), } - }, - ], - }), - AddressRef::Many(GroupRef { - name: Phrase(vec![Word::Atom(&b"Friends"[..])]), - participants: vec![ - MailboxRef{ - name: None, - addrspec: AddrSpec { - local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom(&b"jane"[..]))]), - domain: Domain::Atoms(vec![&b"example"[..], &b"com"[..]]), - } - }, - MailboxRef{ - name: Some(Phrase(vec![Word::Encoded(EncodedWord::Quoted(QuotedWord { - enc: encoding_rs::UTF_8, - chunks: vec![ - QuotedChunk::Safe(&b"John"[..]), - QuotedChunk::Space, - QuotedChunk::Safe(&b"Sm"[..]), - QuotedChunk::Encoded(vec![0xc3, 0xae]), - QuotedChunk::Safe(&b"th"[..]), - ] - }))])), - addrspec: AddrSpec { - local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom(&b"john"[..]))]), - domain: Domain::Atoms(vec![&b"example"[..], &b"com"[..]]), - } - }, - ] - }), - ])) + },], + }), + AddressRef::Many(GroupRef { + name: Phrase(vec![Word::Atom(&b"Friends"[..])]), + participants: vec![ + MailboxRef { + name: None, + addrspec: AddrSpec { + local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom( + &b"jane"[..] + ))]), + domain: Domain::Atoms(vec![&b"example"[..], &b"com"[..]]), + } + }, + MailboxRef { + name: Some(Phrase(vec![Word::Encoded(EncodedWord::Quoted( + QuotedWord { + enc: encoding_rs::UTF_8, + chunks: vec![ + QuotedChunk::Safe(&b"John"[..]), + QuotedChunk::Space, + QuotedChunk::Safe(&b"Sm"[..]), + QuotedChunk::Encoded(vec![0xc3, 0xae]), + QuotedChunk::Safe(&b"th"[..]), + ] + } + ))])), + addrspec: AddrSpec { + local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom( + &b"john"[..] + ))]), + domain: Domain::Atoms(vec![&b"example"[..], &b"com"[..]]), + } + }, + ] + }), + ] + )) ); } } diff --git a/src/imf/field.rs b/src/imf/field.rs index 82c7df6..9ec50c6 100644 --- a/src/imf/field.rs +++ b/src/imf/field.rs @@ -11,9 +11,9 @@ use crate::imf::address::{address_list, mailbox_list, nullable_address_list, Add use crate::imf::datetime::section as date; use crate::imf::identification::{msg_id, msg_list, MessageID, MessageIDList}; use crate::imf::mailbox::{mailbox, AddrSpec, MailboxList, MailboxRef}; -use crate::imf::Imf; use crate::imf::mime::{version, Version}; use crate::imf::trace::{received_log, return_path, ReceivedLog}; +use crate::imf::Imf; use crate::text::misc_token::{phrase_list, unstructured, PhraseList, Unstructured}; use crate::text::whitespace::obs_crlf; diff --git a/src/imf/identification.rs b/src/imf/identification.rs index b6b9cf2..a1a97ac 100644 --- a/src/imf/identification.rs +++ b/src/imf/identification.rs @@ -1,4 +1,3 @@ -use std::fmt; use nom::{ branch::alt, bytes::complete::{tag, take_while}, @@ -7,6 +6,7 @@ use nom::{ sequence::{delimited, pair, tuple}, IResult, }; +use std::fmt; use crate::imf::mailbox::is_dtext; use crate::text::whitespace::cfws; @@ -19,17 +19,22 @@ pub struct MessageID<'a> { } impl<'a> ToString for MessageID<'a> { fn to_string(&self) -> String { - format!("{}@{}", String::from_utf8_lossy(self.left), String::from_utf8_lossy(self.right)) + format!( + "{}@{}", + String::from_utf8_lossy(self.left), + String::from_utf8_lossy(self.right) + ) } } impl<'a> fmt::Debug for MessageID<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("MessageID").field(&format_args!("\"{}\"", self.to_string())).finish() + fmt.debug_tuple("MessageID") + .field(&format_args!("\"{}\"", self.to_string())) + .finish() } } pub type MessageIDList<'a> = Vec>; - /// Message identifier /// /// ```abnf diff --git a/src/imf/mailbox.rs b/src/imf/mailbox.rs index 40641f7..ed30096 100644 --- a/src/imf/mailbox.rs +++ b/src/imf/mailbox.rs @@ -1,4 +1,3 @@ -use std::fmt; use nom::{ branch::alt, bytes::complete::{tag, take_while1}, @@ -7,6 +6,7 @@ use nom::{ sequence::{delimited, pair, preceded, terminated, tuple}, IResult, }; +use std::fmt; use crate::text::ascii; use crate::text::misc_token::{phrase, word, Phrase, Word}; @@ -29,7 +29,9 @@ impl<'a> ToString for AddrSpec<'a> { } impl<'a> fmt::Debug for AddrSpec<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("AddrSpec").field(&format_args!("\"{}\"", self.to_string())).finish() + fmt.debug_tuple("AddrSpec") + .field(&format_args!("\"{}\"", self.to_string())) + .finish() } } @@ -209,7 +211,9 @@ impl<'a> ToString for Domain<'a> { } impl<'a> fmt::Debug for Domain<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Domain").field(&format_args!("\"{}\"", self.to_string())).finish() + fmt.debug_tuple("Domain") + .field(&format_args!("\"{}\"", self.to_string())) + .finish() } } diff --git a/src/imf/mod.rs b/src/imf/mod.rs index d4d044b..9831d05 100644 --- a/src/imf/mod.rs +++ b/src/imf/mod.rs @@ -53,27 +53,26 @@ pub struct Imf<'a> { // it may result in missing data or silently overriden data. impl<'a> FromIterator> for Imf<'a> { fn from_iter>>(iter: I) -> Self { - iter.into_iter() - .fold(Imf::default(), |mut section, field| { - match field { - Field::Date(v) => section.date = v, - Field::From(v) => section.from.extend(v), - Field::Sender(v) => section.sender = Some(v), - Field::ReplyTo(v) => section.reply_to.extend(v), - Field::To(v) => section.to.extend(v), - Field::Cc(v) => section.cc.extend(v), - Field::Bcc(v) => section.bcc.extend(v), - Field::MessageID(v) => section.msg_id = Some(v), - Field::InReplyTo(v) => section.in_reply_to.extend(v), - Field::References(v) => section.references.extend(v), - Field::Subject(v) => section.subject = Some(v), - Field::Comments(v) => section.comments.push(v), - Field::Keywords(v) => section.keywords.push(v), - Field::ReturnPath(v) => v.map(|x| section.return_path.push(x)).unwrap_or(()), - Field::Received(v) => section.received.push(v), - Field::MIMEVersion(v) => section.mime_version = Some(v), - }; - section - }) + iter.into_iter().fold(Imf::default(), |mut section, field| { + match field { + Field::Date(v) => section.date = v, + Field::From(v) => section.from.extend(v), + Field::Sender(v) => section.sender = Some(v), + Field::ReplyTo(v) => section.reply_to.extend(v), + Field::To(v) => section.to.extend(v), + Field::Cc(v) => section.cc.extend(v), + Field::Bcc(v) => section.bcc.extend(v), + Field::MessageID(v) => section.msg_id = Some(v), + Field::InReplyTo(v) => section.in_reply_to.extend(v), + Field::References(v) => section.references.extend(v), + Field::Subject(v) => section.subject = Some(v), + Field::Comments(v) => section.comments.push(v), + Field::Keywords(v) => section.keywords.push(v), + Field::ReturnPath(v) => v.map(|x| section.return_path.push(x)).unwrap_or(()), + Field::Received(v) => section.received.push(v), + Field::MIMEVersion(v) => section.mime_version = Some(v), + }; + section + }) } } diff --git a/src/lib.rs b/src/lib.rs index a94898e..9201079 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ mod error; mod header; +mod imf; mod mime; mod part; -mod imf; mod text; pub fn email(input: &[u8]) -> Result { diff --git a/src/mime/field.rs b/src/mime/field.rs index dfc5e93..bfee691 100644 --- a/src/mime/field.rs +++ b/src/mime/field.rs @@ -6,10 +6,10 @@ use nom::{ }; use crate::header::{field_name, CompFieldList}; +use crate::imf::identification::{msg_id, MessageID}; use crate::mime::mechanism::{mechanism, Mechanism}; use crate::mime::mime::AnyMIME; use crate::mime::r#type::{naive_type, NaiveType}; -use crate::imf::identification::{msg_id, MessageID}; use crate::text::misc_token::{unstructured, Unstructured}; use crate::text::whitespace::obs_crlf; diff --git a/src/mime/mime.rs b/src/mime/mime.rs index 0d23bf1..cd6b675 100644 --- a/src/mime/mime.rs +++ b/src/mime/mime.rs @@ -1,7 +1,7 @@ +use crate::imf::identification::MessageID; use crate::mime::field::Content; use crate::mime::mechanism::Mechanism; use crate::mime::r#type::{self as ctype, AnyType}; -use crate::imf::identification::MessageID; use crate::text::misc_token::Unstructured; //Multipart, Message, Text, Binary}; #[derive(Debug, PartialEq, Clone)] diff --git a/src/mime/type.rs b/src/mime/type.rs index 579d7f0..88a21ff 100644 --- a/src/mime/type.rs +++ b/src/mime/type.rs @@ -1,5 +1,5 @@ use nom::{ - bytes::complete::{tag}, + bytes::complete::tag, combinator::{map, opt}, multi::many0, sequence::{preceded, terminated, tuple}, @@ -260,15 +260,11 @@ mod tests { parameter_list(b";boundary=\"festivus\";"), Ok(( &b""[..], - vec![ - Parameter { - name: &b"boundary"[..], - value: MIMEWord::Quoted(QuotedString(vec![ - &b"festivus"[..] - ])), - } - ], + vec![Parameter { + name: &b"boundary"[..], + value: MIMEWord::Quoted(QuotedString(vec![&b"festivus"[..]])), + }], )) ); - } + } } diff --git a/src/part/composite.rs b/src/part/composite.rs index 032c3b5..b747dbc 100644 --- a/src/part/composite.rs +++ b/src/part/composite.rs @@ -1,16 +1,16 @@ use nom::IResult; use crate::header::{header, CompFieldList}; -use crate::mime; use crate::imf::{self as imf}; +use crate::mime; +use crate::part::{self, AnyPart}; use crate::text::boundary::{boundary, Delimiter}; -use crate::part::{AnyPart, self}; //--- Multipart #[derive(Debug, PartialEq)] pub struct Multipart<'a> { - pub interpreted: mime::mime::Multipart<'a>, - pub children: Vec> + pub interpreted: mime::mime::Multipart<'a>, + pub children: Vec>, } pub fn multipart<'a>( @@ -24,8 +24,24 @@ pub fn multipart<'a>( let mut mparts: Vec = vec![]; loop { let input = match boundary(bound)(input_loop) { - Err(_) => return Ok((input_loop, Multipart { interpreted: m.clone(), children: mparts })), - Ok((inp, Delimiter::Last)) => return Ok((inp, Multipart{ interpreted: m.clone(), children: mparts})), + Err(_) => { + return Ok(( + input_loop, + Multipart { + interpreted: m.clone(), + children: mparts, + }, + )) + } + Ok((inp, Delimiter::Last)) => { + return Ok(( + inp, + Multipart { + interpreted: m.clone(), + children: mparts, + }, + )) + } Ok((inp, Delimiter::Next)) => inp, }; @@ -57,25 +73,32 @@ pub fn message<'a>( m: mime::mime::Message<'a>, ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Message<'a>> { move |input: &[u8]| { - let (input, fields): (_, CompFieldList) = header(part::field::mixed_field)(input)?; + let (input, fields): (_, CompFieldList) = + header(part::field::mixed_field)(input)?; let (in_mime, imf) = fields.sections(); let part = part::to_anypart(in_mime, input); - Ok((&[], Message { interpreted: m.clone(), imf, child: Box::new(part) })) + Ok(( + &[], + Message { + interpreted: m.clone(), + imf, + child: Box::new(part), + }, + )) } } #[cfg(test)] mod tests { use super::*; - use crate::text::encoding::{Base64Word, EncodedWord, QuotedChunk, QuotedWord}; - use crate::text::misc_token::{Phrase, UnstrToken, Unstructured, Word}; use crate::part::discrete::Text; use crate::part::AnyPart; + use crate::text::encoding::{Base64Word, EncodedWord, QuotedChunk, QuotedWord}; + use crate::text::misc_token::{Phrase, UnstrToken, Unstructured, Word}; use chrono::{FixedOffset, TimeZone}; - #[test] fn test_multipart() { let base_mime = mime::mime::Multipart( @@ -109,7 +132,7 @@ This is the epilogue. It is also to be ignored. Multipart { interpreted: base_mime, children: vec![ - AnyPart::Txt(Text { + AnyPart::Txt(Text { interpreted: mime::mime::Text( mime::r#type::Text { subtype: mime::r#type::TextSubtype::Plain, diff --git a/src/part/discrete.rs b/src/part/discrete.rs index 41e5d02..24686d7 100644 --- a/src/part/discrete.rs +++ b/src/part/discrete.rs @@ -4,32 +4,36 @@ use crate::mime; #[derive(PartialEq)] pub struct Text<'a> { - pub interpreted: mime::mime::Text<'a>, - pub body: &'a [u8] + pub interpreted: mime::mime::Text<'a>, + pub body: &'a [u8], } impl<'a> fmt::Debug for Text<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt - .debug_struct("part::Text") + fmt.debug_struct("part::Text") .field("mime", &self.interpreted) - .field("body", &format_args!("\"{}\"", String::from_utf8_lossy(self.body))) + .field( + "body", + &format_args!("\"{}\"", String::from_utf8_lossy(self.body)), + ) .finish() } } #[derive(PartialEq)] pub struct Binary<'a> { - pub interpreted: mime::mime::Binary<'a>, - pub body: &'a [u8] + pub interpreted: mime::mime::Binary<'a>, + pub body: &'a [u8], } impl<'a> fmt::Debug for Binary<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt - .debug_struct("part::Binary") + fmt.debug_struct("part::Binary") .field("mime", &self.interpreted) - .field("body", &format_args!("\"{}\"", String::from_utf8_lossy(self.body))) + .field( + "body", + &format_args!("\"{}\"", String::from_utf8_lossy(self.body)), + ) .finish() } } diff --git a/src/part/field.rs b/src/part/field.rs index b33f3b6..66077bb 100644 --- a/src/part/field.rs +++ b/src/part/field.rs @@ -1,11 +1,7 @@ -use nom::{ - IResult, - branch::alt, - combinator::map, -}; +use nom::{branch::alt, combinator::map, IResult}; -use crate::mime; use crate::imf; +use crate::mime; use crate::part::CompFieldList; pub enum MixedField<'a> { @@ -61,5 +57,3 @@ pub fn mixed_field(input: &[u8]) -> IResult<&[u8], MixedField> { map(imf::field::field, MixedField::IMF), ))(input) } - - diff --git a/src/part/mod.rs b/src/part/mod.rs index fb54023..56341b1 100644 --- a/src/part/mod.rs +++ b/src/part/mod.rs @@ -1,6 +1,6 @@ -pub mod field; pub mod composite; pub mod discrete; +pub mod field; use nom::{ branch::alt, @@ -14,10 +14,13 @@ use nom::{ use crate::header::CompFieldList; use crate::mime; use crate::mime::mime::AnyMIME; +use crate::part::{ + composite::{message, multipart, Message, Multipart}, + discrete::{Binary, Text}, +}; use crate::text::ascii::CRLF; use crate::text::boundary::boundary; use crate::text::whitespace::obs_crlf; -use crate::part::{composite::{Multipart, Message, multipart, message}, discrete::{Text, Binary}}; #[derive(Debug, PartialEq)] pub enum AnyPart<'a> { @@ -31,12 +34,26 @@ pub fn to_anypart<'a>(m: AnyMIME<'a>, rpart: &'a [u8]) -> AnyPart<'a> { match m { AnyMIME::Mult(a) => map(multipart(a), AnyPart::Mult)(rpart) .map(|v| v.1) - .unwrap_or(AnyPart::Txt(Text { interpreted: mime::mime::Text::default(), body: rpart })), - AnyMIME::Msg(a) => map(message(a), AnyPart::Msg)(rpart) - .map(|v| v.1) - .unwrap_or(AnyPart::Txt(Text { interpreted: mime::mime::Text::default(), body: rpart })), - AnyMIME::Txt(a) => AnyPart::Txt(Text { interpreted: a, body: rpart}), - AnyMIME::Bin(a) => AnyPart::Bin(Binary{ interpreted: a, body: rpart }), + .unwrap_or(AnyPart::Txt(Text { + interpreted: mime::mime::Text::default(), + body: rpart, + })), + AnyMIME::Msg(a) => { + map(message(a), AnyPart::Msg)(rpart) + .map(|v| v.1) + .unwrap_or(AnyPart::Txt(Text { + interpreted: mime::mime::Text::default(), + body: rpart, + })) + } + AnyMIME::Txt(a) => AnyPart::Txt(Text { + interpreted: a, + body: rpart, + }), + AnyMIME::Bin(a) => AnyPart::Bin(Binary { + interpreted: a, + body: rpart, + }), } } diff --git a/src/text/boundary.rs b/src/text/boundary.rs index 9d0e490..1ee4c88 100644 --- a/src/text/boundary.rs +++ b/src/text/boundary.rs @@ -1,4 +1,10 @@ -use nom::{branch::alt, bytes::complete::tag, combinator::{eof, opt}, sequence::tuple, IResult}; +use nom::{ + branch::alt, + bytes::complete::tag, + combinator::{eof, opt}, + sequence::tuple, + IResult, +}; use crate::text::whitespace::obs_crlf; diff --git a/src/text/encoding.rs b/src/text/encoding.rs index 4fe8d91..790f640 100644 --- a/src/text/encoding.rs +++ b/src/text/encoding.rs @@ -13,8 +13,8 @@ use nom::{ }; use crate::text::ascii; -use crate::text::words; use crate::text::whitespace::cfws; +use crate::text::words; pub fn encoded_word(input: &[u8]) -> IResult<&[u8], EncodedWord> { alt((encoded_word_quoted, encoded_word_base64))(input) @@ -147,7 +147,7 @@ fn hex_octet(input: &[u8]) -> IResult<&[u8], u8> { let (rest, hbytes) = preceded(tag("="), take(2usize))(input)?; - let hstr = String::from_utf8_lossy(hbytes); + let hstr = String::from_utf8_lossy(hbytes); let parsed = u8::from_str_radix(hstr.as_ref(), 16) .map_err(|_| nom::Err::Error(Error::new(input, ErrorKind::Verify)))?; diff --git a/src/text/misc_token.rs b/src/text/misc_token.rs index acd8b61..29e3318 100644 --- a/src/text/misc_token.rs +++ b/src/text/misc_token.rs @@ -1,4 +1,3 @@ -use std::fmt; use nom::{ branch::alt, bytes::complete::{tag, take_while1}, @@ -8,6 +7,7 @@ use nom::{ sequence::preceded, IResult, }; +use std::fmt; use crate::text::{ ascii, @@ -72,7 +72,9 @@ impl<'a> ToString for Word<'a> { } impl<'a> fmt::Debug for Word<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Word").field(&format_args!("\"{}\"", self.to_string())).finish() + fmt.debug_tuple("Word") + .field(&format_args!("\"{}\"", self.to_string())) + .finish() } } @@ -103,7 +105,9 @@ impl<'a> ToString for Phrase<'a> { } impl<'a> fmt::Debug for Phrase<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Phrase").field(&format_args!("\"{}\"", self.to_string())).finish() + fmt.debug_tuple("Phrase") + .field(&format_args!("\"{}\"", self.to_string())) + .finish() } } @@ -175,7 +179,9 @@ impl<'a> ToString for Unstructured<'a> { } impl<'a> fmt::Debug for Unstructured<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Unstructured").field(&format_args!("\"{}\"", self.to_string())).finish() + fmt.debug_tuple("Unstructured") + .field(&format_args!("\"{}\"", self.to_string())) + .finish() } }