tracklib 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 51bc0c50cee5c08e2a0ab5a48e5a9d4cd00f4db1
4
- data.tar.gz: 496ec85199832aa9cd953d0ef621a5508d03bef0
3
+ metadata.gz: 544377b466a27f1adc1885db2ae638e9c94e14f3
4
+ data.tar.gz: f4e80d1783f605692d0045da784e27a011e432ea
5
5
  SHA512:
6
- metadata.gz: 9ebff64b608756ac55476fc9661249419e746539753e5bcde585f546b08e9a665bb492118b1b2d882670769456b23d80b719952f67b3efcf591b7c49950bcf81
7
- data.tar.gz: e0cdf446ca0fc4f386f186bb4655509a58a4d43e5e41ca9e43f2c8183afdd1d962eeb457bbb5f88dcfa9dcab7165bed896b85e67ed22fb0de7489890bc9da173
6
+ metadata.gz: dd7a4ea44fadb9b2a961fef9ae4c0b811dd1328af6f801074c7440ba1318b0c8a184d0f2e4b9e262cd8e80e11e22b3513a2c4685a4dd2f0f012c878e8270ee42
7
+ data.tar.gz: 4cbaa1f2ee37375cb050acfb4ee38ebd06becc3c37b52e54e4ba3789ee7ef668f205c88e6fdd7d1546f598fdba4bc91066ba5b09aa051c6c2b0b9cfb0d1852ad
data/Cargo.lock CHANGED
@@ -120,8 +120,8 @@ version = "0.1.0"
120
120
  dependencies = [
121
121
  "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
122
122
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
123
- "rutie 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
124
- "rutie-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
123
+ "rutie 0.7.0 (git+https://github.com/danlarkin/rutie)",
124
+ "rutie-serde 0.1.1 (git+https://github.com/danlarkin/rutie-serde)",
125
125
  "tracklib 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
126
126
  ]
127
127
 
@@ -132,8 +132,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
132
132
 
133
133
  [[package]]
134
134
  name = "rutie"
135
- version = "0.5.6"
136
- source = "registry+https://github.com/rust-lang/crates.io-index"
135
+ version = "0.7.0"
136
+ source = "git+https://github.com/danlarkin/rutie#6db74585735ca82894d6163357ee4defdc2cdc61"
137
137
  dependencies = [
138
138
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
139
139
  "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -142,10 +142,10 @@ dependencies = [
142
142
  [[package]]
143
143
  name = "rutie-serde"
144
144
  version = "0.1.1"
145
- source = "registry+https://github.com/rust-lang/crates.io-index"
145
+ source = "git+https://github.com/danlarkin/rutie-serde#de14caea6c73cc479438c0c2b27b528d498e77fc"
146
146
  dependencies = [
147
147
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
148
- "rutie 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
148
+ "rutie 0.7.0 (git+https://github.com/danlarkin/rutie)",
149
149
  "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
150
150
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
151
151
  ]
@@ -241,8 +241,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
241
241
  "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
242
242
  "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
243
243
  "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
244
- "checksum rutie 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5386200cd74705d2f0f6f5076d833ed26070240dea32b778807af38159900284"
245
- "checksum rutie-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d43d8aea0107683e12860daed2e0fa7c36702927c181ecd270552c39dcc94b27"
244
+ "checksum rutie 0.7.0 (git+https://github.com/danlarkin/rutie)" = "<none>"
245
+ "checksum rutie-serde 0.1.1 (git+https://github.com/danlarkin/rutie-serde)" = "<none>"
246
246
  "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
247
247
  "checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113"
248
248
  "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
data/Cargo.toml CHANGED
@@ -5,16 +5,13 @@ authors = ["Dan Larkin <dan@danlarkin.org>"]
5
5
  license = "Apache-2.0 OR MIT"
6
6
  edition = "2018"
7
7
 
8
- [profile.release]
9
- lto = false # LTO broke the ruby module in my testing
10
-
11
8
  [lib]
12
9
  name = "tracklib"
13
10
  crate-type = ["cdylib"]
14
11
 
15
12
  [dependencies]
16
13
  tracklib = "*"
17
- rutie = "0.5"
18
- rutie-serde = "0.1"
14
+ rutie = {git="https://github.com/danlarkin/rutie", features=["no-link"]}
15
+ rutie-serde = {git="https://github.com/danlarkin/rutie-serde"}
19
16
  lazy_static = "1.3"
20
17
  base64 = "0.10"
@@ -1,3 +1,3 @@
1
1
  module Tracklib
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.7"
3
3
  end
data/src/lib.rs CHANGED
@@ -22,10 +22,10 @@ fn any_to_float(o: AnyObject) -> f64 {
22
22
 
23
23
  fn any_to_int(o: AnyObject) -> i64 {
24
24
  match o.try_convert_to::<Integer>() {
25
- Ok(f) => f.to_i64(),
26
- Err(float_e) => o
25
+ Ok(i) => i.to_i64(),
26
+ Err(int_e) => o
27
27
  .try_convert_to::<Float>()
28
- .map_err(|_| VM::raise_ex(float_e))
28
+ .map_err(|_| VM::raise_ex(int_e))
29
29
  .unwrap()
30
30
  .to_f64() as i64,
31
31
  }
@@ -59,7 +59,54 @@ fn any_to_ids(o: AnyObject) -> Vec<u64> {
59
59
  .collect()
60
60
  }
61
61
 
62
- fn convert_config(config: Hash) -> HashMap<String, String> {
62
+ #[derive(Debug, Copy, Clone)]
63
+ enum ColumnType {
64
+ Numbers,
65
+ LongFloat,
66
+ ShortFloat,
67
+ Base64,
68
+ String,
69
+ Bool,
70
+ IDs,
71
+ }
72
+
73
+ impl ColumnType {
74
+ fn from_str(name: &str) -> Option<Self> {
75
+ match name {
76
+ "Number" => Some(ColumnType::Numbers),
77
+ "LongFloat" => Some(ColumnType::LongFloat),
78
+ "ShortFloat" => Some(ColumnType::ShortFloat),
79
+ "Base64" => Some(ColumnType::Base64),
80
+ "String" => Some(ColumnType::String),
81
+ "Bool" => Some(ColumnType::Bool),
82
+ "IDs" => Some(ColumnType::IDs),
83
+ _ => None
84
+ }
85
+ }
86
+
87
+ fn exponent(&self) -> u8 {
88
+ match self {
89
+ ColumnType::Numbers => 48,
90
+ ColumnType::LongFloat => 24,
91
+ ColumnType::ShortFloat => 38,
92
+ _ => {
93
+ VM::raise(Class::from_existing("Exception"),
94
+ &format!("can't handle numeric value for non-numeric field"));
95
+ unreachable!();
96
+ }
97
+ }
98
+ }
99
+
100
+ fn max_integer(&self) -> i64 {
101
+ 2i64.pow(u32::from(self.exponent()))
102
+ }
103
+
104
+ fn max_float(&self) -> f64 {
105
+ 2f64.powi(i32::from(self.exponent()))
106
+ }
107
+ }
108
+
109
+ fn convert_config(config: Hash) -> HashMap<String, ColumnType> {
63
110
  let mut hm = HashMap::new();
64
111
 
65
112
  config.each(|rwtf_type_name, array_of_field_names| {
@@ -67,18 +114,26 @@ fn convert_config(config: Hash) -> HashMap<String, String> {
67
114
  .try_convert_to::<RString>()
68
115
  .map_err(|e| VM::raise_ex(e))
69
116
  .unwrap();
70
- let array_obj = array_of_field_names
71
- .try_convert_to::<Array>()
72
- .map_err(|e| VM::raise_ex(e))
73
- .unwrap();
117
+ let type_name_str = type_name_obj.to_str();
74
118
 
75
- for field_name in array_obj.into_iter() {
76
- let field_name_obj = field_name
77
- .try_convert_to::<RString>()
119
+ if let Some(column_type) = ColumnType::from_str(type_name_str) {
120
+ let array_obj = array_of_field_names
121
+ .try_convert_to::<Array>()
78
122
  .map_err(|e| VM::raise_ex(e))
79
123
  .unwrap();
80
124
 
81
- hm.insert(field_name_obj.to_string(), type_name_obj.to_string());
125
+ for field_name in array_obj.into_iter() {
126
+ let field_name_obj = field_name
127
+ .try_convert_to::<RString>()
128
+ .map_err(|e| VM::raise_ex(e))
129
+ .unwrap();
130
+
131
+ hm.insert(field_name_obj.to_string(), column_type);
132
+ }
133
+ } else {
134
+ VM::raise(Class::from_existing("Exception"),
135
+ &format!("unknown rwtf_field_config type: {}", type_name_str));
136
+ unreachable!();
82
137
  }
83
138
  });
84
139
 
@@ -99,39 +154,98 @@ fn is_empty_array(v: &AnyObject) -> bool {
99
154
  }
100
155
  }
101
156
 
102
- fn is_number_too_large(v: &AnyObject) -> bool {
103
- match v.try_convert_to::<Integer>() {
104
- Ok(i) => i.to_i64().abs() > 2i64.pow(48),
105
- Err(_) => match v.try_convert_to::<Float>() {
106
- Ok(f) => f.to_f64().abs() > 2f64.powi(48),
107
- Err(_) => false
157
+ fn is_number_and_too_large(v: &AnyObject, field_type: ColumnType) -> bool {
158
+ // First we have to try to cast `v` to a numeric type (Integer or Float)
159
+ // and then call to_i64/f64(). This will raise an exception if the number
160
+ // is too large to turn into a primitive.
161
+ let is_number_result = VM::protect(|| {
162
+ match v.try_convert_to::<Integer>() {
163
+ Ok(i) => {
164
+ let _ = i.to_i64(); // force a conversion
165
+ Boolean::new(true)
166
+ }
167
+ Err(_) => match v.try_convert_to::<Float>() {
168
+ Ok(f) => {
169
+ let _ = f.to_f64(); // force a conversion
170
+ Boolean::new(true)
171
+ }
172
+ Err(_) => Boolean::new(false)
173
+ }
174
+ }.to_any_object()
175
+ });
176
+
177
+ match is_number_result {
178
+ Ok(is_number) => {
179
+ // Here we know that no exception was raised during the attempted primitive conversion.
180
+ // We also know that `is_number` is a Boolean, so this unsafe cast is fine.
181
+ if unsafe { is_number.to::<Boolean>().to_bool() } {
182
+ match v.try_convert_to::<Integer>() {
183
+ Ok(i) => i.to_i64().abs() > field_type.max_integer(),
184
+ Err(_) => match v.try_convert_to::<Float>() {
185
+ Ok(f) => f.to_f64().abs() > field_type.max_float(),
186
+ Err(_) => false
187
+ }
188
+ }
189
+ } else {
190
+ false
191
+ }
192
+ }
193
+ Err(_) => {
194
+ VM::clear_error_info(); // clear ruby VM error register
195
+ true // this IS a number and it IS too large
108
196
  }
109
197
  }
110
198
  }
111
199
 
112
- fn add_points(points: Array, mut callback: impl FnMut(usize, &str, AnyObject)) {
113
- for (i, maybe_point) in points.into_iter().enumerate() {
114
- let point = maybe_point
115
- .try_convert_to::<Hash>()
116
- .map_err(|e| VM::raise_ex(e))
117
- .unwrap();
118
-
119
- point.each(|k, v| {
120
- let field_name_obj = k
121
- .try_convert_to::<RString>()
200
+ fn add_points(source: &Hash,
201
+ section_points_config: &HashMap<String, ColumnType>,
202
+ section_type: &str,
203
+ mut callback: impl FnMut(usize, &str, DataField)) {
204
+ let maybe_section_points = source
205
+ .at(&RString::new_utf8(section_type))
206
+ .try_convert_to::<Array>();
207
+
208
+ if let Ok(section_points) = maybe_section_points {
209
+ for (i, maybe_point) in section_points.into_iter().enumerate() {
210
+ let point = maybe_point
211
+ .try_convert_to::<Hash>()
122
212
  .map_err(|e| VM::raise_ex(e))
123
213
  .unwrap();
124
- let name = field_name_obj.to_str();
125
-
126
- if !v.is_nil()
127
- && !name.is_empty()
128
- && !is_empty_string(&v)
129
- && !is_empty_array(&v)
130
- && !is_number_too_large(&v)
131
- {
132
- callback(i, name, v);
133
- }
134
- });
214
+
215
+ point.each(|k: AnyObject, v: AnyObject| {
216
+ let field_name_obj = k
217
+ .try_convert_to::<RString>()
218
+ .map_err(|e| VM::raise_ex(e))
219
+ .unwrap();
220
+ let name = field_name_obj.to_str();
221
+
222
+ if !name.is_empty() {
223
+ if let Some(field_type) = section_points_config.get(name) {
224
+ if !v.is_nil()
225
+ && !is_empty_string(&v)
226
+ && !is_empty_array(&v)
227
+ && !is_number_and_too_large(&v, *field_type)
228
+ {
229
+ let data = match field_type {
230
+ ColumnType::LongFloat => DataField::LongFloat(any_to_float(v)),
231
+ ColumnType::ShortFloat => DataField::ShortFloat(any_to_float(v)),
232
+ ColumnType::Numbers => DataField::Number(any_to_int(v)),
233
+ ColumnType::Base64 => DataField::Base64(any_to_str(v).replace("\n", "")),
234
+ ColumnType::String => DataField::String(any_to_str(v)),
235
+ ColumnType::Bool => DataField::Bool(any_to_bool(v)),
236
+ ColumnType::IDs => DataField::IDs(any_to_ids(v)),
237
+ };
238
+
239
+ callback(i, name, data);
240
+ }
241
+ } else {
242
+ VM::raise(Module::from_existing("Tracklib").get_nested_class("UnknownFieldError"),
243
+ &format!("unknown {} field: {}", section_type, name));
244
+ unreachable!();
245
+ }
246
+ }
247
+ });
248
+ }
135
249
  }
136
250
  }
137
251
 
@@ -223,79 +337,21 @@ methods!(
223
337
  RWTFile::new()
224
338
  };
225
339
 
226
- let maybe_track_points = source
227
- .at(&RString::new_utf8("track_points"))
228
- .try_convert_to::<Array>();
229
-
230
- if let Ok(track_points) = maybe_track_points {
231
- add_points(track_points, |i, k, v| {
232
- let data = if let Some(field_type) = track_points_config.get(k) {
233
- match field_type.as_str() {
234
- "LongFloat" => DataField::LongFloat(any_to_float(v)),
235
- "ShortFloat" => DataField::ShortFloat(any_to_float(v)),
236
- "Number" => DataField::Number(any_to_int(v)),
237
- "Base64" => DataField::Base64(any_to_str(v).replace("\n", "")),
238
- "String" => DataField::String(any_to_str(v)),
239
- "Bool" => DataField::Bool(any_to_bool(v)),
240
- "IDs" => DataField::IDs(any_to_ids(v)),
241
- _ => {
242
- VM::raise(
243
- Class::from_existing("Exception"),
244
- &format!("unknown track_points type: {}", field_type),
245
- );
246
- unreachable!();
247
- }
248
- }
249
- } else {
250
- VM::raise(Module::from_existing("Tracklib").get_nested_class("UnknownFieldError"),
251
- &format!("unknown track_points field: {}", k));
252
- unreachable!();
253
- };
254
-
255
- rwtf.add_track_point(i, k, data)
256
- .map_err(|e| {
257
- VM::raise(Class::from_existing("Exception"), &format!("{}", e))
258
- })
259
- .unwrap();
260
- });
261
- }
262
-
263
- let maybe_course_points = source
264
- .at(&RString::new_utf8("course_points"))
265
- .try_convert_to::<Array>();
266
-
267
- if let Ok(course_points) = maybe_course_points {
268
- add_points(course_points, |i, k, v| {
269
- let data = if let Some(field_type) = course_points_config.get(k) {
270
- match field_type.as_str() {
271
- "LongFloat" => DataField::LongFloat(any_to_float(v)),
272
- "ShortFloat" => DataField::ShortFloat(any_to_float(v)),
273
- "Number" => DataField::Number(any_to_int(v)),
274
- "Base64" => DataField::Base64(any_to_str(v).replace("\n", "")),
275
- "String" => DataField::String(any_to_str(v)),
276
- "Bool" => DataField::Bool(any_to_bool(v)),
277
- "IDs" => DataField::IDs(any_to_ids(v)),
278
- _ => {
279
- VM::raise(
280
- Class::from_existing("Exception"),
281
- &format!("unknown course_points type: {}", field_type),
282
- );
283
- unreachable!();
284
- }
285
- }
286
- } else {
287
- VM::raise(Module::from_existing("Tracklib").get_nested_class("UnknownFieldError"),
288
- &format!("unknown course_points field: {}", k));
289
- unreachable!();
290
- };
340
+ add_points(&source, &track_points_config, "track_points", |i, name, data| {
341
+ rwtf.add_track_point(i, name, data)
342
+ .map_err(|e| {
343
+ VM::raise(Class::from_existing("Exception"), &format!("{}", e))
344
+ })
345
+ .unwrap();
346
+ });
291
347
 
292
- rwtf.add_course_point(i, k, data)
293
- .map_err(|e| {
294
- VM::raise(Class::from_existing("Exception"), &format!("{}", e))
295
- })
296
- .unwrap();
297
- });
298
- }
348
+ add_points(&source, &course_points_config, "course_points", |i, name, data| {
349
+ rwtf.add_course_point(i, name, data)
350
+ .map_err(|e| {
351
+ VM::raise(Class::from_existing("Exception"), &format!("{}", e))
352
+ })
353
+ .unwrap();
354
+ });
299
355
 
300
356
  let inner = Inner { inner: rwtf };
301
357
  Class::from_existing("RWTFile").wrap_data(inner, &*INNER_WRAPPER)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tracklib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Larkin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-19 00:00:00.000000000 Z
11
+ date: 2019-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec