Reputation: 8112
I work with a bunch of structs / enums included in each other. I need to get ty.node<TyKind::Path>.1.segments.last().identifiers
and ty.node<TyKind::Path>.1.segments.last().parameters<AngleBracketed::AngleBracketed>.types
.
Is there a simpler way to get these two values then my implementation of f
? My ideal syntax would be:
ty.node<TyKind::Path>?.1.segments.last().identifiers
// and
ty.node<TyKind::Path>?.1.segments.last().parameters<AngleBracketed::AngleBracketed>?.types
It that's impossible, maybe there is a way to reduce the number of if let
? I want to solve only this particular case, so simplification should be possible compared to f
. If an analog of Option::map
/ Option::unwrap_or_else
were introduced, then the sum of its code + the code in f
should be less then my original f
.
#[derive(Clone)]
struct Ty {
node: TyKind,
}
#[derive(Clone)]
enum TyKind {
Path(Option<i32>, Path),
}
#[derive(Clone)]
struct Path {
segments: Vec<PathSegment>,
}
#[derive(Clone)]
struct PathSegment {
identifier: String,
parameters: Option<Box<PathParameters>>,
}
#[derive(Clone)]
enum PathParameters {
AngleBracketed(AngleBracketedParameterData),
}
#[derive(Clone)]
struct AngleBracketedParameterData {
types: Vec<Box<Ty>>,
}
/// If Tylnode == Path -> return last path segment + types
fn f(ty: &Ty) -> Option<(String, Vec<Box<Ty>>)> {
match ty.node {
TyKind::Path(_, ref path) => if let Some(seg) = path.segments.iter().last() {
let ident = seg.identifier.clone();
println!("next_ty: seg.id {:?}", seg.identifier);
match seg.parameters.as_ref() {
Some(params) => match **params {
PathParameters::AngleBracketed(ref params) => {
Some((ident, params.types.clone()))
}
_ => Some((ident, vec![])),
},
None => Some((ident, vec![])),
}
} else {
None
},
_ => None,
}
}
To simplify the question, I have removed unrelated enum variants and struct fields.
Upvotes: 2
Views: 390
Reputation: 3861
No.
The closest you can get, using nightly features and helper code, is probably this
fn f(ty: &Ty) -> MyOption<(String, Vec<Box<Ty>>)> {
let last = ty.node.path()?.segments.my_last()?;
Just((
last.identifier.clone(),
last.ab_parameters()
.map(|v| v.types.clone())
.unwrap_or_else(|| vec![]),
))
}
Upvotes: 2
Reputation:
I guess what you want is called Lenses. Not sure about Rust, but here is about Haskell https://en.m.wikibooks.org/wiki/Haskell/Lenses_and_functional_references
It might be possible to implement that in Rust, if somebody haven't done yet.
Upvotes: 0