@@ -6,10 +6,10 @@ use crate::error::{LoftyError, Result};
66use crate :: id3:: v2:: frame:: FrameRef ;
77use crate :: id3:: v2:: items:: encoded_text_frame:: EncodedTextFrame ;
88use crate :: id3:: v2:: items:: language_frame:: LanguageFrame ;
9- use crate :: picture:: { Picture , PictureType } ;
9+ use crate :: picture:: { Picture , PictureType , TOMBSTONE_PICTURE } ;
1010use crate :: tag:: item:: { ItemKey , ItemValue , TagItem } ;
1111use crate :: tag:: { Tag , TagType } ;
12- use crate :: traits:: { Accessor , TagExt } ;
12+ use crate :: traits:: { Accessor , SplitAndRejoinTag , TagExt } ;
1313use crate :: util:: text:: TextEncoding ;
1414
1515use std:: borrow:: Cow ;
@@ -533,8 +533,8 @@ impl TagExt for ID3v2Tag {
533533 }
534534}
535535
536- impl From < ID3v2Tag > for Tag {
537- fn from ( input : ID3v2Tag ) -> Self {
536+ impl SplitAndRejoinTag for ID3v2Tag {
537+ fn split_tag ( & mut self ) -> Tag {
538538 fn split_pair (
539539 content : & str ,
540540 tag : & mut Tag ,
@@ -555,13 +555,13 @@ impl From<ID3v2Tag> for Tag {
555555 Some ( ( ) )
556556 }
557557
558- let mut tag = Self :: new ( TagType :: ID3v2 ) ;
558+ let mut tag = Tag :: new ( TagType :: ID3v2 ) ;
559559
560- for frame in input . frames {
561- let id = frame. id ;
560+ self . frames . retain_mut ( |frame| {
561+ let id = & frame. id ;
562562
563563 // The text pairs need some special treatment
564- match ( id. as_str ( ) , frame. value ) {
564+ match ( id. as_str ( ) , & mut frame. value ) {
565565 ( "TRCK" , FrameValue :: Text { value : content, .. } )
566566 if split_pair (
567567 & content,
@@ -571,13 +571,13 @@ impl From<ID3v2Tag> for Tag {
571571 )
572572 . is_some ( ) =>
573573 {
574- continue
574+ false // Frame consumed
575575 } ,
576576 ( "TPOS" , FrameValue :: Text { value : content, .. } )
577577 if split_pair ( & content, & mut tag, ItemKey :: DiscNumber , ItemKey :: DiscTotal )
578578 . is_some ( ) =>
579579 {
580- continue
580+ false // Frame consumed
581581 } ,
582582 ( "MVIN" , FrameValue :: Text { value : content, .. } )
583583 if split_pair (
@@ -588,7 +588,7 @@ impl From<ID3v2Tag> for Tag {
588588 )
589589 . is_some ( ) =>
590590 {
591- continue
591+ false // Frame consumed
592592 } ,
593593 // Store TXXX/WXXX frames by their descriptions, rather than their IDs
594594 (
@@ -606,6 +606,7 @@ impl From<ID3v2Tag> for Tag {
606606 ItemValue :: Text ( c. to_string ( ) ) ,
607607 ) ) ;
608608 }
609+ false // Frame consumed
609610 } ,
610611 (
611612 "WXXX" ,
@@ -622,6 +623,7 @@ impl From<ID3v2Tag> for Tag {
622623 ItemValue :: Locator ( c. to_string ( ) ) ,
623624 ) ) ;
624625 }
626+ false // Frame consumed
625627 } ,
626628 ( id, value) => {
627629 let item_key = ItemKey :: from_key ( TagType :: ID3v2 , id) ;
@@ -642,22 +644,22 @@ impl From<ID3v2Tag> for Tag {
642644 description,
643645 ..
644646 } ) => {
645- if description == EMPTY_CONTENT_DESCRIPTOR {
647+ if * description == EMPTY_CONTENT_DESCRIPTOR {
646648 for c in content. split ( V4_MULTI_VALUE_SEPARATOR ) {
647649 tag. items . push ( TagItem :: new (
648650 item_key. clone ( ) ,
649651 ItemValue :: Text ( c. to_string ( ) ) ,
650652 ) ) ;
651653 }
654+ return false ; // Frame consumed
652655 }
653656 // ...else do not convert text frames with a non-empty content
654657 // descriptor that would otherwise unintentionally be modified
655658 // and corrupted by the incomplete conversion into a [`TagItem`].
656659 // TODO: How to convert these frames consistently and safely
657660 // such that the content descriptor is preserved during read/write
658661 // round trips?
659-
660- continue ;
662+ return true ; // Keep frame
661663 } ,
662664 FrameValue :: Text { value : content, .. } => {
663665 for c in content. split ( V4_MULTI_VALUE_SEPARATOR ) {
@@ -666,34 +668,34 @@ impl From<ID3v2Tag> for Tag {
666668 ItemValue :: Text ( c. to_string ( ) ) ,
667669 ) ) ;
668670 }
669-
670- continue ;
671+ return false ; // Frame consumed
671672 } ,
672673 FrameValue :: URL ( content)
673- | FrameValue :: UserURL ( EncodedTextFrame { content, .. } ) => ItemValue :: Locator ( content) ,
674+ | FrameValue :: UserURL ( EncodedTextFrame { content, .. } ) => {
675+ ItemValue :: Locator ( std:: mem:: take ( content) )
676+ } ,
674677 FrameValue :: Picture { picture, .. } => {
675- tag. push_picture ( picture) ;
676- continue ;
678+ tag. push_picture ( std :: mem :: replace ( picture, TOMBSTONE_PICTURE ) ) ;
679+ return false ; // Frame consumed
677680 } ,
678681 FrameValue :: Popularimeter ( popularimeter) => {
679682 ItemValue :: Binary ( popularimeter. as_bytes ( ) )
680683 } ,
681- FrameValue :: Binary ( binary) => ItemValue :: Binary ( binary) ,
684+ FrameValue :: Binary ( binary) => ItemValue :: Binary ( std :: mem :: take ( binary) ) ,
682685 } ;
683686
684687 tag. items . push ( TagItem :: new ( item_key, item_value) ) ;
688+ false // Frame consumed
685689 } ,
686690 }
687- }
691+ } ) ;
688692
689693 tag
690694 }
691- }
692695
693- impl From < Tag > for ID3v2Tag {
694- fn from ( mut input : Tag ) -> Self {
695- fn join_items ( input : & mut Tag , key : & ItemKey ) -> String {
696- let mut iter = input. take_strings ( key) ;
696+ fn rejoin_tag ( & mut self , mut tag : Tag ) {
697+ fn join_items ( tag : & mut Tag , key : & ItemKey ) -> String {
698+ let mut iter = tag. take_strings ( key) ;
697699
698700 match iter. next ( ) {
699701 None => String :: new ( ) ,
@@ -710,25 +712,22 @@ impl From<Tag> for ID3v2Tag {
710712 }
711713 }
712714
713- let mut id3v2_tag = ID3v2Tag {
714- frames : Vec :: with_capacity ( input. item_count ( ) as usize ) ,
715- ..ID3v2Tag :: default ( )
716- } ;
715+ self . frames . reserve ( tag. item_count ( ) as usize ) ;
717716
718- let artists = join_items ( & mut input , & ItemKey :: TrackArtist ) ;
719- id3v2_tag . set_artist ( artists) ;
717+ let artists = join_items ( & mut tag , & ItemKey :: TrackArtist ) ;
718+ self . set_artist ( artists) ;
720719
721- for item in input . items {
720+ for item in tag . items {
722721 let frame: Frame < ' _ > = match item. into ( ) {
723722 Some ( frame) => frame,
724723 None => continue ,
725724 } ;
726725
727- id3v2_tag . insert ( frame) ;
726+ self . insert ( frame) ;
728727 }
729728
730- for picture in input . pictures {
731- id3v2_tag . frames . push ( Frame {
729+ for picture in tag . pictures {
730+ self . frames . push ( Frame {
732731 id : FrameID :: Valid ( Cow :: Borrowed ( "APIC" ) ) ,
733732 value : FrameValue :: Picture {
734733 encoding : TextEncoding :: UTF8 ,
@@ -737,7 +736,19 @@ impl From<Tag> for ID3v2Tag {
737736 flags : FrameFlags :: default ( ) ,
738737 } )
739738 }
739+ }
740+ }
741+
742+ impl From < ID3v2Tag > for Tag {
743+ fn from ( mut input : ID3v2Tag ) -> Self {
744+ input. split_tag ( )
745+ }
746+ }
740747
748+ impl From < Tag > for ID3v2Tag {
749+ fn from ( input : Tag ) -> Self {
750+ let mut id3v2_tag = ID3v2Tag :: default ( ) ;
751+ id3v2_tag. rejoin_tag ( input) ;
741752 id3v2_tag
742753 }
743754}
0 commit comments