Skip to content
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

Removes the separate no_text_values collection in Struct #430

Merged
merged 4 commits into from
Sep 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ num-integer = "0.1.44"
num-traits = "0.2"
arrayvec = "0.7"
hashlink = "0.8.1"
smallvec = "1.9.0"

[dev-dependencies]
rstest = "0.9"
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod raw_symbol_token_ref;
mod reader;
mod stream_reader;
mod symbol;
mod symbol_ref;
mod symbol_table;
mod system_reader;
mod writer;
Expand Down
87 changes: 87 additions & 0 deletions src/symbol_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use crate::Symbol;

/// A reference to a fully resolved symbol. Like `Symbol` (a fully resolved symbol with a
/// static lifetime), a `SymbolRef` may have known or undefined text.
#[derive(Debug, PartialEq, Eq)]
pub struct SymbolRef<'a> {
text: Option<&'a str>,
}

impl<'a> SymbolRef<'a> {
/// If this symbol has known text, returns `Some(&str)`. Otherwise, returns `None`.
pub fn text(&self) -> Option<&str> {
self.text
}

/// Constructs a `SymbolRef` with unknown text.
pub fn with_unknown_text() -> Self {
SymbolRef { text: None }
}

/// Constructs a `SymbolRef` with the specified text.
pub fn with_text(text: &str) -> SymbolRef {
SymbolRef { text: Some(text) }
}
}

/// Allows a `SymbolRef` to be constructed from a source value. This enables non-symbol types to be
/// viewed as a symbol with little to no runtime overhead.
pub trait AsSymbolRef {
fn as_symbol_ref(&self) -> SymbolRef;
}

// All text types can be viewed as a `SymbolRef`.
impl<'a, A: AsRef<str> + 'a> AsSymbolRef for A {
fn as_symbol_ref(&self) -> SymbolRef {
SymbolRef {
text: Some(self.as_ref()),
}
}
}

// Owned `Symbol` values can be viewed as a `SymbolRef`. Due to lifetime conflicts in the
// trait definitions, this cannot be achieved with `AsRef` or `Borrow`.
impl AsSymbolRef for Symbol {
fn as_symbol_ref(&self) -> SymbolRef {
self.text()
.map(SymbolRef::with_text)
.unwrap_or_else(SymbolRef::with_unknown_text)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn symbol_ref_with_text() {
let symbol_ref = SymbolRef::with_text("foo");
assert_eq!(Some("foo"), symbol_ref.text());
}

#[test]
fn symbol_ref_with_unknown_text() {
let symbol_ref = SymbolRef::with_unknown_text();
assert_eq!(None, symbol_ref.text());
}

#[test]
fn str_as_symbol_ref() {
let symbol_ref: SymbolRef = "foo".as_symbol_ref();
assert_eq!(Some("foo"), symbol_ref.text());
}

#[test]
fn symbol_as_symbol_ref() {
let symbol = Symbol::owned("foo");
let symbol_ref: SymbolRef = symbol.as_symbol_ref();
assert_eq!(Some("foo"), symbol_ref.text());
}

#[test]
fn symbol_with_unknown_text_as_symbol_ref() {
let symbol = Symbol::unknown_text();
let symbol_ref: SymbolRef = symbol.as_symbol_ref();
assert_eq!(None, symbol_ref.text());
}
}
32 changes: 19 additions & 13 deletions src/value/borrowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! backed by octets or string data, `&[u8]` and `&str` are used.

use super::{IonElement, IonSequence, IonStruct, IonSymbolToken};
use crate::symbol_ref::AsSymbolRef;
use crate::types::decimal::Decimal;
use crate::types::integer::Integer;
use crate::types::timestamp::Timestamp;
Expand Down Expand Up @@ -293,24 +294,29 @@ impl<'val> IonStruct for StructRef<'val> {
)
}

fn get<T: AsRef<str>>(&self, field_name: T) -> Option<&Self::Element> {
self.text_fields
.get(field_name.as_ref())?
.last()
.map(|(_s, v)| v)
fn get<T: AsSymbolRef>(&self, field_name: T) -> Option<&Self::Element> {
if let Some(text) = field_name.as_symbol_ref().text() {
self.text_fields.get(text)?.last().map(|(_s, v)| v)
} else {
self.no_text_fields.last().map(|(_name, value)| value)
desaikd marked this conversation as resolved.
Show resolved Hide resolved
}
}

fn get_all<'a, T: AsRef<str>>(
fn get_all<'a, T: AsSymbolRef>(
&'a self,
field_name: T,
) -> Box<dyn Iterator<Item = &'a Self::Element> + 'a> {
Box::new(
self.text_fields
.get(field_name.as_ref())
.into_iter()
.flat_map(|v| v.iter())
.map(|(_s, v)| v),
)
if let Some(text) = field_name.as_symbol_ref().text() {
Box::new(
self.text_fields
.get(text)
.into_iter()
.flat_map(|v| v.iter())
.map(|(_s, v)| v),
)
} else {
Box::new(self.no_text_fields.iter().map(|(_name, value)| value))
}
}
}

desaikd marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
5 changes: 3 additions & 2 deletions src/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@
//! [simd-json-value]: https://docs.rs/simd-json/latest/simd_json/value/index.html
//! [serde-json-value]: https://docs.serde.rs/serde_json/value/enum.Value.html

use crate::symbol_ref::AsSymbolRef;
use crate::types::decimal::Decimal;
use crate::types::integer::Integer;
use crate::types::timestamp::Timestamp;
Expand Down Expand Up @@ -490,7 +491,7 @@ pub trait IonStruct: Debug + PartialEq {
/// let owned: Struct = fields.into_iter().collect();
/// assert_eq!("d", owned.get("c".to_string()).map(|e| e.as_str()).flatten().unwrap());
/// ```
fn get<T: AsRef<str>>(&self, field_name: T) -> Option<&Self::Element>;
fn get<T: AsSymbolRef>(&self, field_name: T) -> Option<&Self::Element>;

/// Returns an iterator with all the values corresponding to the field_name in the struct or
/// returns an empty iterator if the field_name does not exist in the struct
Expand Down Expand Up @@ -521,7 +522,7 @@ pub trait IonStruct: Debug + PartialEq {
/// owned.get_all("d").flat_map(|e| e.as_str()).collect::<Vec<&str>>()
/// );
/// ```
fn get_all<'a, T: AsRef<str>>(
fn get_all<'a, T: AsSymbolRef>(
&'a self,
field_name: T,
) -> Box<dyn Iterator<Item = &'a Self::Element> + 'a>;
Expand Down
Loading