-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Trying to implement whosonfirst/whosonfirst-cookbook#35
- Loading branch information
Showing
5 changed files
with
250 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod ser; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ use structopt::StructOpt; | |
|
||
mod commands; | ||
mod git; | ||
mod ser; | ||
mod std; | ||
|
||
#[derive(Debug, StructOpt)] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
use json::codegen::Generator; | ||
use json::object::Object; | ||
use json::JsonValue; | ||
use std::io::{self, Write}; | ||
|
||
pub struct WOFGenerator<'a, W> { | ||
writer: &'a mut W, | ||
dent: u16, | ||
} | ||
|
||
impl<'a, W> WOFGenerator<'a, W> | ||
where | ||
W: Write, | ||
{ | ||
pub fn new(writer: &'a mut W) -> WOFGenerator<W> { | ||
WOFGenerator { | ||
writer: writer, | ||
dent: 0, | ||
} | ||
} | ||
|
||
pub fn write_object_value_by_key(&mut self, key: &str, value: &JsonValue) -> io::Result<()> { | ||
match key { | ||
"bbox" => { | ||
if let JsonValue::Array(ref array) = value { | ||
self.write_char(b'[')?; | ||
let mut iter = array.iter(); | ||
|
||
if let Some(item) = iter.next() { | ||
self.indent(); | ||
self.new_line()?; | ||
self.write_json(item)?; | ||
} else { | ||
self.write_char(b']')?; | ||
return Ok(()); | ||
} | ||
|
||
for item in iter { | ||
self.write_char(b',')?; | ||
self.new_line()?; | ||
self.write_json(item)?; | ||
} | ||
|
||
self.dedent(); | ||
self.write_char(b'\n')?; | ||
self.write_char(b']') | ||
} else { | ||
self.write_json(value) | ||
} | ||
} | ||
"geometry" => value.write(&mut self.writer), | ||
_ => self.write_json(value), | ||
} | ||
} | ||
} | ||
|
||
impl<'a, W> Generator for WOFGenerator<'a, W> | ||
where | ||
W: Write, | ||
{ | ||
type T = W; | ||
|
||
#[inline(always)] | ||
fn get_writer(&mut self) -> &mut W { | ||
&mut self.writer | ||
} | ||
|
||
#[inline(always)] | ||
fn write_min(&mut self, colon_space: &[u8], colon: u8) -> io::Result<()> { | ||
if self.dent == 1 { | ||
self.writer.write_all(colon_space) | ||
} else { | ||
self.writer.write_all(&[colon]) | ||
} | ||
} | ||
|
||
#[inline(always)] | ||
fn write_object(&mut self, object: &Object) -> io::Result<()> { | ||
self.write_char(b'{')?; | ||
let mut entries: Vec<(&str, &JsonValue)> = Vec::new(); | ||
for (k, v) in object.iter() { | ||
entries.push((k, v)); | ||
} | ||
if self.dent == 0 { | ||
entries.sort_by(wof_first_level_ordering); | ||
} else { | ||
entries.sort_by(|(k1, _), (k2, _)| k1.partial_cmp(k2).unwrap()); | ||
} | ||
let mut iter = entries.iter(); | ||
if let Some((key, value)) = iter.next() { | ||
self.indent(); | ||
self.new_line()?; | ||
self.write_string(key)?; | ||
self.write_min(b": ", b':')?; | ||
self.write_object_value_by_key(key, value)?; | ||
} else { | ||
self.write_char(b'}')?; | ||
return Ok(()); | ||
} | ||
|
||
for (key, value) in iter { | ||
self.write_char(b',')?; | ||
self.new_line()?; | ||
self.write_string(key)?; | ||
self.write_min(b": ", b':')?; | ||
self.write_object_value_by_key(key, value)?; | ||
} | ||
|
||
self.dedent(); | ||
self.new_line()?; | ||
self.write_char(b'}') | ||
} | ||
|
||
fn indent(&mut self) { | ||
self.dent += 1; | ||
} | ||
|
||
fn dedent(&mut self) { | ||
self.dent -= 1; | ||
} | ||
|
||
fn new_line(&mut self) -> io::Result<()> { | ||
self.write_char(b'\n')?; | ||
for _ in 0..(self.dent * 2) { | ||
self.write_char(b' ')?; | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
fn wof_first_level_classify(key: &str) -> i32 { | ||
match key { | ||
"id" => 0, | ||
"type" => 1, | ||
"properties" => 2, | ||
"bbox" => 4, | ||
"geometry" => 5, | ||
_ => 3, | ||
} | ||
} | ||
|
||
fn wof_first_level_ordering( | ||
(k1, _): &(&str, &JsonValue), | ||
(k2, _): &(&str, &JsonValue), | ||
) -> std::cmp::Ordering { | ||
if wof_first_level_classify(k1) < wof_first_level_classify(k2) { | ||
std::cmp::Ordering::Less | ||
} else if wof_first_level_classify(k1) > wof_first_level_classify(k2) { | ||
std::cmp::Ordering::Greater | ||
} else { | ||
k1.partial_cmp(k2).unwrap() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#[macro_use] | ||
extern crate json; | ||
|
||
use json::codegen::Generator; | ||
use json::Null; | ||
use wof::ser::WOFGenerator; | ||
|
||
#[test] | ||
pub fn serialize_first_level_wof_geojson_with_null() { | ||
let t = object! { | ||
"type"=> Null, | ||
"properties"=> Null, | ||
"geometry"=> Null, | ||
"bbox"=> Null, | ||
"id"=> Null, | ||
}; | ||
let mut vec: Vec<u8> = Vec::new(); | ||
assert!(WOFGenerator::new(&mut vec).write_json(&t).is_ok()); | ||
assert_eq!( | ||
String::from_utf8(vec).unwrap(), | ||
r#"{ | ||
"id": null, | ||
"type": null, | ||
"properties": null, | ||
"bbox": null, | ||
"geometry": null | ||
}"# | ||
); | ||
} | ||
|
||
#[test] | ||
pub fn serialize_first_level_wof_geojson_with_content() { | ||
let t = object! { | ||
"type"=>"Feature", | ||
"properties"=> object!{ | ||
"name:fra_x_preferred" => vec![ | ||
"Ajaccio" | ||
], | ||
"wof:id"=>101748927, | ||
"wof:lang" => vec![ | ||
"fre" | ||
], | ||
"name:eng_x_preferred" => vec![ | ||
"Ajaccio" | ||
], | ||
}, | ||
"geometry"=> object!{ | ||
"coordinates" => vec![vec![ | ||
vec![8.585396,41.873571], | ||
vec![8.826011,41.873571], | ||
vec![8.826011,41.971536], | ||
vec![8.585396,41.968222], | ||
vec![8.585396,41.873571] | ||
]], | ||
"type" => "Polygon" | ||
}, | ||
"bbox"=> vec![ | ||
8.585396, | ||
41.873571, | ||
8.826011, | ||
41.971536 | ||
], | ||
"id"=> 101748927, | ||
}; | ||
let mut vec: Vec<u8> = Vec::new(); | ||
assert!(WOFGenerator::new(&mut vec).write_json(&t).is_ok()); | ||
assert_eq!( | ||
String::from_utf8(vec).unwrap(), | ||
r#"{ | ||
"id": 101748927, | ||
"type": "Feature", | ||
"properties": { | ||
"name:eng_x_preferred":[ | ||
"Ajaccio" | ||
], | ||
"name:fra_x_preferred":[ | ||
"Ajaccio" | ||
], | ||
"wof:id":101748927, | ||
"wof:lang":[ | ||
"fre" | ||
] | ||
}, | ||
"bbox": [ | ||
8.585396, | ||
41.873571, | ||
8.826011, | ||
41.971536 | ||
], | ||
"geometry": {"coordinates":[[[8.585396,41.873571],[8.826011,41.873571],[8.826011,41.971536],[8.585396,41.968222],[8.585396,41.873571]]],"type":"Polygon"} | ||
}"# | ||
); | ||
} |