ucg/src/convert/json.rs
Jeremy Wall 5fba06d71f Add json as an output type.
* Uses serde_json
* Doesn't handle macro values very well.
* Handles maps and lists just fine.
* doesn't pretty print the values though.
2018-02-04 16:08:30 -06:00

86 lines
2.9 KiB
Rust

// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::rc::Rc;
use std::io::Write;
use std::io::Result;
use serde_json;
use ast;
use build::Val;
use convert::traits::Converter;
pub struct JsonConverter {}
impl JsonConverter {
pub fn new() -> Self {
JsonConverter {}
}
fn convert_list(&self, items: &Vec<Rc<Val>>) -> Result<serde_json::Value> {
let mut v = Vec::new();
for val in items.iter() {
v.push(try!(self.convert_value(val)));
}
Ok(serde_json::Value::Array(v))
}
fn convert_tuple(&self, items: &Vec<(ast::Positioned<String>, Rc<Val>)>) -> Result<serde_json::Value> {
let mut mp = serde_json::Map::new();
for &(ref k, ref v) in items.iter() {
mp.entry(k.val.clone()).or_insert(try!(self.convert_value(v)));
}
Ok(serde_json::Value::Object(mp))
}
fn convert_value(&self, v: &Val) -> Result<serde_json::Value> {
let jsn_val = match v {
&Val::Float(f) => {
let n = match serde_json::Number::from_f64(f) {
Some(n) => n,
// In theory this should never happen. But on the off chance that it does...
None => panic!("Float is too large or Not a Number {}", f),
};
serde_json::Value::Number(n)
},
&Val::Int(i) => {
let n = match serde_json::Number::from_f64(i as f64) {
Some(n) => n,
// In theory this should never happen. But on the off chance that it does...
None => panic!("Float is too large or Not a Number {}", i),
};
serde_json::Value::Number(n)
},
&Val::String(ref s) => serde_json::Value::String(s.clone()),
&Val::Macro(_) => {
// TODO(jwall): We probably want to actually skip this but for now
// we'll use null
eprintln!("Skipping macro encoding as null...");
serde_json::Value::Null
},
&Val::List(ref l) => try!(self.convert_list(l)),
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
};
Ok(jsn_val)
}
fn write(&self, v: &Val, w: &mut Write) -> Result<()> {
let jsn_val = try!(self.convert_value(v));
try!(serde_json::to_writer(w, &jsn_val));
Ok(())
}
}
impl Converter for JsonConverter {
fn convert(&self, v: Rc<Val>, mut w: Box<Write>) -> Result<()> {
self.write(&v, &mut w)
}
}