@@ -4,12 +4,12 @@ use std::ops::{Add, Range, Sub};
4
4
5
5
use crate :: coord:: ranged1d:: {
6
6
AsRangedCoord , DefaultFormatting , DiscreteRanged , KeyPointHint , NoDefaultFormatting , Ranged ,
7
- ValueFormatter ,
7
+ ReversibleRanged , ValueFormatter ,
8
8
} ;
9
9
10
10
/// The trait that describe some time value. This is the uniformed abstraction that works
11
11
/// for both Date, DateTime and Duration, etc.
12
- pub trait TimeValue : Eq {
12
+ pub trait TimeValue : Eq + Sized {
13
13
type DateType : Datelike + PartialOrd ;
14
14
15
15
/// Returns the date that is no later than the time
@@ -20,6 +20,8 @@ pub trait TimeValue: Eq {
20
20
fn earliest_after_date ( date : Self :: DateType ) -> Self ;
21
21
/// Returns the duration between two time value
22
22
fn subtract ( & self , other : & Self ) -> Duration ;
23
+ /// Add duration to time value
24
+ fn add ( & self , duration : & Duration ) -> Self ;
23
25
/// Instantiate a date type for current time value;
24
26
fn ymd ( & self , year : i32 , month : u32 , date : u32 ) -> Self :: DateType ;
25
27
/// Cast current date type into this type
@@ -46,6 +48,31 @@ pub trait TimeValue: Eq {
46
48
47
49
( f64:: from ( limit. 1 - limit. 0 ) * value_days / total_days) as i32 + limit. 0
48
50
}
51
+
52
+ /// Map pixel to coord spec
53
+ fn unmap_coord ( point : i32 , begin : & Self , end : & Self , limit : ( i32 , i32 ) ) -> Self {
54
+ let total_span = end. subtract ( begin) ;
55
+ let offset = ( point - limit. 0 ) as i64 ;
56
+
57
+ // Check if nanoseconds fit in i64
58
+ if let Some ( total_ns) = total_span. num_nanoseconds ( ) {
59
+ let pixel_span = ( limit. 1 - limit. 0 ) as i64 ;
60
+ let factor = total_ns / pixel_span;
61
+ let remainder = total_ns % pixel_span;
62
+ if factor == 0
63
+ || i64:: MAX / factor > offset. abs ( )
64
+ || ( remainder == 0 && i64:: MAX / factor >= offset. abs ( ) )
65
+ {
66
+ let nano_seconds = offset * factor + ( remainder * offset) / pixel_span;
67
+ return begin. add ( & Duration :: nanoseconds ( nano_seconds) ) ;
68
+ }
69
+ }
70
+
71
+ // Otherwise, use days
72
+ let total_days = total_span. num_days ( ) as f64 ;
73
+ let days = ( ( ( offset as f64 ) * total_days) / ( ( limit. 1 - limit. 0 ) as f64 ) ) as i64 ;
74
+ begin. add ( & Duration :: days ( days) )
75
+ }
49
76
}
50
77
51
78
impl TimeValue for NaiveDate {
@@ -62,6 +89,9 @@ impl TimeValue for NaiveDate {
62
89
fn subtract ( & self , other : & NaiveDate ) -> Duration {
63
90
* self - * other
64
91
}
92
+ fn add ( & self , other : & Duration ) -> NaiveDate {
93
+ * self + * other
94
+ }
65
95
66
96
fn ymd ( & self , year : i32 , month : u32 , date : u32 ) -> Self :: DateType {
67
97
NaiveDate :: from_ymd ( year, month, date)
@@ -86,6 +116,9 @@ impl<Z: TimeZone> TimeValue for Date<Z> {
86
116
fn subtract ( & self , other : & Date < Z > ) -> Duration {
87
117
self . clone ( ) - other. clone ( )
88
118
}
119
+ fn add ( & self , other : & Duration ) -> Date < Z > {
120
+ self . clone ( ) + * other
121
+ }
89
122
90
123
fn ymd ( & self , year : i32 , month : u32 , date : u32 ) -> Self :: DateType {
91
124
self . timezone ( ) . ymd ( year, month, date)
@@ -115,6 +148,9 @@ impl<Z: TimeZone> TimeValue for DateTime<Z> {
115
148
fn subtract ( & self , other : & DateTime < Z > ) -> Duration {
116
149
self . clone ( ) - other. clone ( )
117
150
}
151
+ fn add ( & self , other : & Duration ) -> DateTime < Z > {
152
+ self . clone ( ) + * other
153
+ }
118
154
119
155
fn ymd ( & self , year : i32 , month : u32 , date : u32 ) -> Self :: DateType {
120
156
self . timezone ( ) . ymd ( year, month, date)
@@ -144,6 +180,9 @@ impl TimeValue for NaiveDateTime {
144
180
fn subtract ( & self , other : & NaiveDateTime ) -> Duration {
145
181
* self - * other
146
182
}
183
+ fn add ( & self , other : & Duration ) -> NaiveDateTime {
184
+ * self + * other
185
+ }
147
186
148
187
fn ymd ( & self , year : i32 , month : u32 , date : u32 ) -> Self :: DateType {
149
188
NaiveDate :: from_ymd ( year, month, date)
@@ -663,6 +702,19 @@ where
663
702
}
664
703
}
665
704
705
+ impl < DT > ReversibleRanged for RangedDateTime < DT >
706
+ where
707
+ DT : Datelike + Timelike + TimeValue + Clone + PartialOrd ,
708
+ DT : Add < Duration , Output = DT > ,
709
+ DT : Sub < DT , Output = Duration > ,
710
+ RangedDate < DT :: DateType > : Ranged < ValueType = DT :: DateType > ,
711
+ {
712
+ /// Perform the reverse mapping
713
+ fn unmap ( & self , input : i32 , limit : ( i32 , i32 ) ) -> Option < Self :: ValueType > {
714
+ Some ( TimeValue :: unmap_coord ( input, & self . 0 , & self . 1 , limit) )
715
+ }
716
+ }
717
+
666
718
/// The coordinate that for duration of time
667
719
#[ derive( Clone ) ]
668
720
pub struct RangedDuration ( Duration , Duration ) ;
@@ -1168,4 +1220,76 @@ mod test {
1168
1220
assert_eq ! ( coord1. index_of( & coord1. from_index( i) . unwrap( ) ) . unwrap( ) , i) ;
1169
1221
}
1170
1222
}
1223
+
1224
+ #[ test]
1225
+ fn test_datetime_with_unmap ( ) {
1226
+ let start_time = Utc . ymd ( 2021 , 1 , 1 ) . and_hms ( 8 , 0 , 0 ) ;
1227
+ let end_time = Utc . ymd ( 2023 , 1 , 1 ) . and_hms ( 8 , 0 , 0 ) ;
1228
+ let mid = Utc . ymd ( 2022 , 1 , 1 ) . and_hms ( 8 , 0 , 0 ) ;
1229
+ let coord: RangedDateTime < _ > = ( start_time..end_time) . into ( ) ;
1230
+ let pos = coord. map ( & mid, ( 1000 , 2000 ) ) ;
1231
+ assert_eq ! ( pos, 1500 ) ;
1232
+ let value = coord. unmap ( pos, ( 1000 , 2000 ) ) ;
1233
+ assert_eq ! ( value, Some ( mid) ) ;
1234
+ }
1235
+
1236
+ #[ test]
1237
+ fn test_naivedatetime_with_unmap ( ) {
1238
+ let start_time = NaiveDate :: from_ymd ( 2021 , 1 , 1 ) . and_hms_milli ( 8 , 0 , 0 , 0 ) ;
1239
+ let end_time = NaiveDate :: from_ymd ( 2023 , 1 , 1 ) . and_hms_milli ( 8 , 0 , 0 , 0 ) ;
1240
+ let mid = NaiveDate :: from_ymd ( 2022 , 1 , 1 ) . and_hms_milli ( 8 , 0 , 0 , 0 ) ;
1241
+ let coord: RangedDateTime < _ > = ( start_time..end_time) . into ( ) ;
1242
+ let pos = coord. map ( & mid, ( 1000 , 2000 ) ) ;
1243
+ assert_eq ! ( pos, 1500 ) ;
1244
+ let value = coord. unmap ( pos, ( 1000 , 2000 ) ) ;
1245
+ assert_eq ! ( value, Some ( mid) ) ;
1246
+ }
1247
+
1248
+ #[ test]
1249
+ fn test_date_with_unmap ( ) {
1250
+ let start_date = Utc . ymd ( 2021 , 1 , 1 ) ;
1251
+ let end_date = Utc . ymd ( 2023 , 1 , 1 ) ;
1252
+ let mid = Utc . ymd ( 2022 , 1 , 1 ) ;
1253
+ let coord: RangedDate < Date < _ > > = ( start_date..end_date) . into ( ) ;
1254
+ let pos = coord. map ( & mid, ( 1000 , 2000 ) ) ;
1255
+ assert_eq ! ( pos, 1500 ) ;
1256
+ let value = coord. unmap ( pos, ( 1000 , 2000 ) ) ;
1257
+ assert_eq ! ( value, Some ( mid) ) ;
1258
+ }
1259
+
1260
+ #[ test]
1261
+ fn test_naivedate_with_unmap ( ) {
1262
+ let start_date = NaiveDate :: from_ymd ( 2021 , 1 , 1 ) ;
1263
+ let end_date = NaiveDate :: from_ymd ( 2023 , 1 , 1 ) ;
1264
+ let mid = NaiveDate :: from_ymd ( 2022 , 1 , 1 ) ;
1265
+ let coord: RangedDate < NaiveDate > = ( start_date..end_date) . into ( ) ;
1266
+ let pos = coord. map ( & mid, ( 1000 , 2000 ) ) ;
1267
+ assert_eq ! ( pos, 1500 ) ;
1268
+ let value = coord. unmap ( pos, ( 1000 , 2000 ) ) ;
1269
+ assert_eq ! ( value, Some ( mid) ) ;
1270
+ }
1271
+
1272
+ #[ test]
1273
+ fn test_datetime_unmap_for_nanoseconds ( ) {
1274
+ let start_time = Utc . ymd ( 2021 , 1 , 1 ) . and_hms ( 8 , 0 , 0 ) ;
1275
+ let end_time = start_time + Duration :: nanoseconds ( 1900 ) ;
1276
+ let mid = start_time + Duration :: nanoseconds ( 950 ) ;
1277
+ let coord: RangedDateTime < _ > = ( start_time..end_time) . into ( ) ;
1278
+ let pos = coord. map ( & mid, ( 1000 , 2000 ) ) ;
1279
+ assert_eq ! ( pos, 1500 ) ;
1280
+ let value = coord. unmap ( pos, ( 1000 , 2000 ) ) ;
1281
+ assert_eq ! ( value, Some ( mid) ) ;
1282
+ }
1283
+
1284
+ #[ test]
1285
+ fn test_datetime_unmap_for_nanoseconds_small_period ( ) {
1286
+ let start_time = Utc . ymd ( 2021 , 1 , 1 ) . and_hms ( 8 , 0 , 0 ) ;
1287
+ let end_time = start_time + Duration :: nanoseconds ( 400 ) ;
1288
+ let coord: RangedDateTime < _ > = ( start_time..end_time) . into ( ) ;
1289
+ let value = coord. unmap ( 2000 , ( 1000 , 2000 ) ) ;
1290
+ assert_eq ! ( value, Some ( end_time) ) ;
1291
+ let mid = start_time + Duration :: nanoseconds ( 200 ) ;
1292
+ let value = coord. unmap ( 500 , ( 0 , 1000 ) ) ;
1293
+ assert_eq ! ( value, Some ( mid) ) ;
1294
+ }
1171
1295
}
0 commit comments