@@ -3,16 +3,18 @@ use rss;
33
44use std:: str:: FromStr ;
55use chrono:: { DateTime , UTC } ;
6+
67use link:: Link ;
78use person:: Person ;
89use generator:: Generator ;
9-
1010use category:: Category ;
1111use entry:: Entry ;
12+ use image:: Image ;
13+ use text_input:: TextInput ;
1214
1315enum FeedData {
1416 Atom ( atom:: Feed ) ,
15- RSS ( rss:: Channel ) ,
17+ Rss ( rss:: Channel ) ,
1618}
1719
1820// A helpful table of approximately equivalent elements can be found here:
@@ -36,29 +38,47 @@ pub struct Feed {
3638 // `icon` in Atom, not present in RSS
3739 pub icon : Option < String > ,
3840 // `logo` in Atom, and `image` in RSS
39- pub image : Option < String > ,
41+ pub image : Option < Image > ,
4042
4143 // `generator` in both Atom and RSS
4244 pub generator : Option < Generator > ,
4345 // `links` in Atom, and `link` in RSS (produces a 1 item Vec)
4446 pub links : Vec < Link > ,
4547 // `categories` in both Atom and RSS
4648 pub categories : Vec < Category > ,
47- // TODO: Should the `web_master` be in `contributors`, `authors`, or at all?
4849 // `authors` in Atom, `managing_editor` in RSS (produces 1 item Vec)
50+ // TODO: Should the `web_master` be in `contributors`, `authors`, or at all?
4951 pub authors : Vec < Person > ,
5052 // `contributors` in Atom, `web_master` in RSS (produces a 1 item Vec)
5153 pub contributors : Vec < Person > ,
5254 // `entries` in Atom, and `items` in RSS
53- // TODO: Add more fields that are necessary for RSS
5455 // TODO: Fancy translation, e.g. Atom <link rel="via"> = RSS `source`
5556 pub entries : Vec < Entry > ,
57+
58+ // TODO: Add more fields that are necessary for RSS
59+ // `ttl` in RSS, not present in Atom
60+ pub ttl : Option < String > ,
61+ // `skip_hours` in RSS, not present in Atom
62+ pub skip_hours : Option < String > ,
63+ // `skip_days` in RSS, not present in Atom
64+ pub skip_days : Option < String > ,
65+ // `text_input` in RSS, not present in Atom
66+ pub text_input : Option < TextInput > ,
67+ // `language` in RSS, not present in Atom
68+ pub language : Option < String > ,
69+ // `docs` in RSS, not present in Atom
70+ pub docs : Option < String > ,
71+ // `rating` in RSS, not present in Atom
72+ pub rating : Option < String > ,
5673}
5774
5875impl From < atom:: Feed > for Feed {
5976 fn from ( feed : atom:: Feed ) -> Self {
77+ let feed_clone = feed. clone ( ) ;
78+ let title = feed. title . clone ( ) ;
79+ let link = feed. links . first ( ) . map_or_else ( || "" . into ( ) , |link| link. href . clone ( ) ) ;
6080 Feed {
61- source_data : Some ( FeedData :: Atom ( feed . clone ( ) ) ) ,
81+ source_data : Some ( FeedData :: Atom ( feed_clone ) ) ,
6282 id : Some ( feed. id ) ,
6383 title : feed. title ,
6484 description : feed. subtitle ,
@@ -67,7 +87,17 @@ impl From<atom::Feed> for Feed {
6787 . map ( |date| date. with_timezone ( & UTC ) ) ,
6888 copyright : feed. rights ,
6989 icon : feed. icon ,
70- image : feed. logo ,
90+ // (Note, in practice the image <title> and <link> should have the same value as the
91+ // channel's <title> and <link>.)
92+ image : feed. logo . map ( |url| {
93+ Image {
94+ url : url,
95+ title : title,
96+ link : link,
97+ width : None ,
98+ height : None ,
99+ }
100+ } ) ,
71101 generator : feed. generator . map ( |generator| generator. into ( ) ) ,
72102 links : feed. links . into_iter ( ) . map ( |link| link. into ( ) ) . collect ( ) ,
73103 categories : feed. categories . into_iter ( ) . map ( |person| person. into ( ) ) . collect ( ) ,
@@ -77,6 +107,13 @@ impl From<atom::Feed> for Feed {
77107 . into_iter ( )
78108 . map ( |entry| entry. into ( ) )
79109 . collect :: < Vec < _ > > ( ) ,
110+ ttl : None ,
111+ skip_hours : None ,
112+ skip_days : None ,
113+ text_input : None ,
114+ language : None ,
115+ docs : None ,
116+ rating : None ,
80117 }
81118 }
82119}
@@ -97,7 +134,7 @@ impl From<Feed> for atom::Feed {
97134 updated : feed. updated . unwrap_or_else ( UTC :: now) . to_rfc3339 ( ) ,
98135 rights : feed. copyright ,
99136 icon : feed. icon ,
100- logo : feed. image ,
137+ logo : feed. image . map ( |image| image . url ) ,
101138 generator : None ,
102139 links : feed. links . into_iter ( ) . map ( |link| link. into ( ) ) . collect ( ) ,
103140 categories : feed. categories . into_iter ( ) . map ( |category| category. into ( ) ) . collect ( ) ,
@@ -112,14 +149,71 @@ impl From<Feed> for atom::Feed {
112149 }
113150}
114151
152+ impl From < rss:: Channel > for Feed {
153+ fn from ( feed : rss:: Channel ) -> Self {
154+ Feed {
155+ source_data : Some ( FeedData :: Rss ( feed. clone ( ) ) ) ,
156+ id : None ,
157+ title : feed. title ,
158+ description : Some ( feed. description ) ,
159+ updated : None ,
160+ copyright : feed. copyright ,
161+ icon : None ,
162+ image : feed. image . map ( |image| image. into ( ) ) ,
163+ generator : feed. generator . map ( Generator :: from_name) ,
164+ links : vec ! [ Link :: from_href( feed. link) ] ,
165+ categories : feed. categories . into_iter ( ) . map ( |person| person. into ( ) ) . collect ( ) ,
166+ authors : feed. managing_editor . into_iter ( ) . map ( Person :: from_name) . collect ( ) ,
167+ contributors : feed. web_master . into_iter ( ) . map ( Person :: from_name) . collect ( ) ,
168+ entries : feed. items . into_iter ( ) . map ( |entry| entry. into ( ) ) . collect ( ) ,
169+ ttl : feed. ttl ,
170+ skip_hours : feed. skip_hours ,
171+ skip_days : feed. skip_days ,
172+ text_input : feed. text_input . map ( |input| input. into ( ) ) ,
173+ rating : feed. rating ,
174+ language : feed. language ,
175+ docs : feed. docs ,
176+ }
177+ }
178+ }
179+
180+ impl From < Feed > for rss:: Channel {
181+ fn from ( feed : Feed ) -> rss:: Channel {
182+ if let Some ( FeedData :: Rss ( feed) ) = feed. source_data {
183+ feed
184+ } else {
185+ rss:: Channel {
186+ title : feed. title ,
187+ description : feed. description . unwrap_or ( "" . into ( ) ) ,
188+ pub_date : None ,
189+ last_build_date : feed. updated . map ( |date| date. to_rfc2822 ( ) ) ,
190+ link : feed. links . into_iter ( ) . next ( ) . map_or_else ( || "" . into ( ) , |link| link. href ) ,
191+ items : feed. entries . into_iter ( ) . map ( |entry| entry. into ( ) ) . collect ( ) ,
192+ categories : feed. categories . into_iter ( ) . map ( |category| category. into ( ) ) . collect ( ) ,
193+ image : feed. image . map ( |image| image. into ( ) ) ,
194+ generator : feed. generator . map ( |generator| generator. name ) ,
195+ managing_editor : feed. authors . into_iter ( ) . next ( ) . map ( |person| person. name ) ,
196+ web_master : feed. contributors . into_iter ( ) . next ( ) . map ( |person| person. name ) ,
197+ copyright : feed. copyright ,
198+ ttl : feed. ttl ,
199+ skip_hours : feed. skip_hours ,
200+ skip_days : feed. skip_days ,
201+ text_input : feed. text_input . map ( |input| input. into ( ) ) ,
202+ rating : feed. rating ,
203+ language : feed. language ,
204+ docs : feed. docs ,
205+ }
206+ }
207+ }
208+ }
209+
115210impl FromStr for Feed {
116211 type Err = & ' static str ;
117212
118213 fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
119214 match s. parse :: < FeedData > ( ) {
120215 Ok ( FeedData :: Atom ( feed) ) => Ok ( feed. into ( ) ) ,
121- // TODO: Implement the RSS conversions
122- Ok ( FeedData :: RSS ( _) ) => Err ( "RSS Unimplemented" ) ,
216+ Ok ( FeedData :: Rss ( feed) ) => Ok ( feed. into ( ) ) ,
123217 Err ( e) => Err ( e) ,
124218 }
125219 }
@@ -133,7 +227,7 @@ impl FromStr for FeedData {
133227 Ok ( feed) => Ok ( FeedData :: Atom ( feed) ) ,
134228 _ => {
135229 match s. parse :: < rss:: Rss > ( ) {
136- Ok ( rss:: Rss ( channel) ) => Ok ( FeedData :: RSS ( channel) ) ,
230+ Ok ( rss:: Rss ( channel) ) => Ok ( FeedData :: Rss ( channel) ) ,
137231 _ => Err ( "Could not parse XML as Atom or RSS from input" ) ,
138232 }
139233 }
@@ -145,7 +239,7 @@ impl ToString for FeedData {
145239 fn to_string ( & self ) -> String {
146240 match * self {
147241 FeedData :: Atom ( ref atom_feed) => atom_feed. to_string ( ) ,
148- FeedData :: RSS ( ref rss_channel) => rss:: Rss ( rss_channel. clone ( ) ) . to_string ( ) ,
242+ FeedData :: Rss ( ref rss_channel) => rss:: Rss ( rss_channel. clone ( ) ) . to_string ( ) ,
149243 }
150244 }
151245}
@@ -226,7 +320,7 @@ mod test {
226320 ..Default :: default ( )
227321 } ;
228322
229- let rss = FeedData :: RSS ( channel) ;
323+ let rss = FeedData :: Rss ( channel) ;
230324 assert_eq ! ( rss. to_string( ) ,
231325 "<?xml version=\' 1.0\' encoding=\' UTF-8\' ?><rss \
232326 version=\' 2.0\' ><channel><title>My \
0 commit comments