-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Promotes head
, improves inspect
#118
Changes from all commits
c6c4d2e
1a27ba9
19dde61
5461006
c3e2f6e
91c7982
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ use std::fmt::Display; | |
use std::io::Write; | ||
use std::str::FromStr; | ||
|
||
use anyhow::{Context, Result}; | ||
use anyhow::{bail, Context, Result}; | ||
use clap::{Arg, ArgMatches, Command}; | ||
use ion_rs::v1_0::{LazyRawBinaryValue, RawValueRef}; | ||
use ion_rs::*; | ||
|
@@ -187,22 +187,39 @@ impl<'a, 'b> IonInspector<'a, 'b> { | |
Ok(inspector) | ||
} | ||
|
||
fn confirm_encoding_is_supported(&self, encoding: IonEncoding) -> Result<()> { | ||
use IonEncoding::*; | ||
match encoding { | ||
Text_1_0 | Text_1_1 => { | ||
bail!("`inspect` does not support text Ion streams."); | ||
} | ||
Binary_1_0 => Ok(()), | ||
Binary_1_1 => bail!("`inspect` does not yet support binary Ion v1.1"), | ||
// `IonEncoding` is #[non_exhaustive] | ||
_ => bail!("`inspect does not yet support {}", encoding.name()), | ||
} | ||
} | ||
Comment on lines
+190
to
+201
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗺️ The latest |
||
|
||
/// Iterates over the items in `reader`, printing a table section for each top level value. | ||
fn inspect_top_level<Input: IonInput>( | ||
&mut self, | ||
reader: &mut SystemReader<AnyEncoding, Input>, | ||
) -> Result<()> { | ||
const TOP_LEVEL_DEPTH: usize = 0; | ||
self.write_table_header()?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗺️ We now defer writing the table header until after we've read the first item from the stream and confirmed it's of a supported encoding. |
||
|
||
let mut is_first_item = true; | ||
let mut has_printed_skip_message = false; | ||
loop { | ||
// TODO: This does not account for shared symbol table imports. However, the CLI does not | ||
// yet support specifying a catalog, so it's correct enough for the moment. | ||
let mut next_symbol_id = reader.symbol_table().len(); | ||
let item = reader.next_item()?; | ||
let is_last_item = matches!(item, SystemStreamItem::EndOfStream(_)); | ||
|
||
if is_first_item { | ||
// The first item in a stream cannot be ephemeral, so we can safely unwrap this. | ||
let encoding = item.raw_stream_item().unwrap().encoding(); | ||
self.confirm_encoding_is_supported(encoding)?; | ||
self.write_table_header()?; | ||
} | ||
|
||
match self.select_action( | ||
TOP_LEVEL_DEPTH, | ||
&mut has_printed_skip_message, | ||
|
@@ -222,17 +239,13 @@ impl<'a, 'b> IonInspector<'a, 'b> { | |
|
||
match item { | ||
SystemStreamItem::SymbolTable(lazy_struct) => { | ||
let is_append = lazy_struct.get("imports")? | ||
== Some(ValueRef::Symbol(SymbolRef::with_text("$ion_symbol_table"))); | ||
if !is_append { | ||
next_symbol_id = 10; // First available SID after system symbols in Ion 1.0 | ||
} | ||
self.inspect_symbol_table(next_symbol_id, lazy_struct)?; | ||
Comment on lines
-225
to
-230
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗺️ Now that a |
||
self.inspect_symbol_table(lazy_struct)?; | ||
} | ||
SystemStreamItem::Value(lazy_value) => { | ||
self.inspect_value(0, "", lazy_value, no_comment())?; | ||
} | ||
SystemStreamItem::VersionMarker(marker) => { | ||
self.confirm_encoding_is_supported(marker.encoding())?; | ||
self.inspect_ivm(marker)?; | ||
} | ||
SystemStreamItem::EndOfStream(_) => { | ||
|
@@ -462,11 +475,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { | |
} | ||
} | ||
|
||
fn inspect_symbol_table( | ||
&mut self, | ||
next_symbol_id: usize, | ||
struct_: LazyStruct<'_, AnyEncoding>, | ||
) -> Result<()> { | ||
fn inspect_symbol_table(&mut self, struct_: LazyStruct<'_, AnyEncoding>) -> Result<()> { | ||
let value = struct_.as_value(); | ||
if value.has_annotations() { | ||
self.newline()?; | ||
|
@@ -479,9 +488,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { | |
|
||
use LazyRawValueKind::*; | ||
match raw_struct.as_value().kind() { | ||
Binary_1_0(v) => { | ||
self.inspect_binary_1_0_symbol_table(next_symbol_id, struct_, raw_struct, v) | ||
} | ||
Binary_1_0(v) => self.inspect_binary_1_0_symbol_table(struct_, raw_struct, v), | ||
Binary_1_1(_) => todo!("Binary Ion 1.1 symbol table"), | ||
Text_1_0(_) | Text_1_1(_) => unreachable!("text value"), | ||
} | ||
|
@@ -742,7 +749,6 @@ impl<'a, 'b> IonInspector<'a, 'b> { | |
|
||
fn inspect_binary_1_0_symbol_table( | ||
&mut self, | ||
next_symbol_id: usize, | ||
struct_: LazyStruct<AnyEncoding>, | ||
raw_struct: LazyRawAnyStruct, | ||
raw_value: LazyRawBinaryValue, | ||
|
@@ -771,7 +777,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { | |
)? { | ||
InspectorAction::Skip => continue, | ||
InspectorAction::Inspect if field.name()? == "symbols" => { | ||
self.inspect_lst_symbols_field(next_symbol_id, field, raw_field)? | ||
self.inspect_lst_symbols_field(struct_, field, raw_field)? | ||
} | ||
// TODO: if field.name()? == "imports" => {} | ||
InspectorAction::Inspect => { | ||
|
@@ -791,7 +797,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { | |
|
||
fn inspect_lst_symbols_field( | ||
&mut self, | ||
mut next_symbol_id: usize, | ||
symtab_struct: LazyStruct<AnyEncoding>, | ||
field: LazyField<AnyEncoding>, | ||
raw_field: LazyRawFieldExpr<AnyEncoding>, | ||
) -> Result<()> { | ||
|
@@ -825,6 +831,16 @@ impl<'a, 'b> IonInspector<'a, 'b> { | |
Ok(()) | ||
})?; | ||
|
||
// TODO: This does not account for shared symbol table imports. However, the CLI does not | ||
// yet support specifying a catalog, so it's correct enough for the moment. | ||
let symtab_value = symtab_struct.as_value(); | ||
let mut next_symbol_id = symtab_value.symbol_table().len(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗺️ We don't have to track which ID we were on because we can ask the symbol table what the next ID will be. |
||
let is_append = symtab_struct.get("imports")? | ||
== Some(ValueRef::Symbol(SymbolRef::with_text("$ion_symbol_table"))); | ||
if !is_append { | ||
next_symbol_id = 10; // First available SID after system symbols in Ion 1.0 | ||
} | ||
|
||
let mut has_printed_skip_message = false; | ||
for (raw_value_res, value_res) in nested_raw_values.zip(nested_values) { | ||
let (raw_nested_value, nested_value) = (raw_value_res?, value_res?); | ||
|
@@ -925,15 +941,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { | |
BytesKind::TrailingLength, | ||
encoding.trailing_length_span().bytes(), | ||
); | ||
// TODO: There is a bug in the `body_span()` method that causes it fail when the value is annotated. | ||
// When it's fixed, this can be: | ||
// let body_bytes = IonBytes::new(BytesKind::ValueBody, body_span); | ||
let body_len = raw_value.encoded_data().body_range().len(); | ||
let total_len = raw_value.encoded_data().range().len(); | ||
let body_bytes = IonBytes::new( | ||
BytesKind::ValueBody, | ||
&encoding.span().bytes()[total_len - body_len..], | ||
); | ||
let body_bytes = IonBytes::new(BytesKind::ValueBody, encoding.body_span().bytes()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗺️ |
||
|
||
let mut formatter = | ||
BytesFormatter::new(BYTES_PER_ROW, vec![opcode_bytes, length_bytes, body_bytes]); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ use termcolor::{ColorChoice, StandardStream, StandardStreamLock}; | |
pub mod beta; | ||
pub mod cat; | ||
pub mod dump; | ||
pub mod head; | ||
pub mod inspect; | ||
|
||
/// Behaviors common to all Ion CLI commands, including both namespaces (groups of commands) | ||
|
@@ -51,7 +52,8 @@ pub trait IonCliCommand { | |
.about(self.about()) | ||
.version(crate_version!()) | ||
.author(crate_authors!()) | ||
.hide(self.hide_from_help_message()); | ||
.hide(self.hide_from_help_message()) | ||
.with_compression_control(); | ||
|
||
// If there are subcommands, add them to the configuration and set 'subcommand_required'. | ||
if !clap_subcommands.is_empty() { | ||
|
@@ -175,8 +177,8 @@ impl<'a> CommandIo<'a> { | |
|
||
/// Returns `true` if the user has not explicitly disabled auto decompression. | ||
fn auto_decompression_enabled(&self) -> bool { | ||
if let Some(flag) = self.args.get_one::<bool>("no-auto-decompress") { | ||
!*flag | ||
if let Some(is_disabled) = self.args.get_one::<bool>("no-auto-decompress") { | ||
!*is_disabled | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗺️ This is just a naming change for clarity. |
||
} else { | ||
true | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ use ion_rs::IonError; | |
use std::io::ErrorKind; | ||
|
||
use crate::commands::dump::DumpCommand; | ||
use crate::commands::head::HeadCommand; | ||
use crate::commands::inspect::InspectCommand; | ||
|
||
fn main() -> Result<()> { | ||
|
@@ -48,8 +49,9 @@ impl IonCliCommand for RootCommand { | |
fn subcommands(&self) -> Vec<Box<dyn IonCliCommand>> { | ||
vec![ | ||
Box::new(BetaNamespace), | ||
Box::new(DumpCommand), | ||
Box::new(CatCommand), | ||
Box::new(DumpCommand), | ||
Box::new(HeadCommand), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗺️ I put the commands in alphabetical order while I was here. |
||
Box::new(InspectCommand), | ||
] | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -201,7 +201,6 @@ fn test_write_all_values(#[case] number: i32, #[case] expected_output: &str) -> | |
input_file.write_all(test_data.as_bytes())?; | ||
input_file.flush()?; | ||
cmd.args([ | ||
"beta", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗺️ This unit test invoked |
||
"head", | ||
"--values", | ||
&number.to_string(), | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗺️ Prior to this PR, commands needed to explicitly opt into supporting the
--no-auto-decompress
flag. Forgetting to do so would cause the program to ugly-crash when the flag was specified. Now the flag is supported universally by default.