Comments (7)
The biggest problem of your current approach is that it won't accept string. The reason is that only references to sized types can be cast to trait references, but str
is not sized and therefore &str
won't cast to &std::fmt::Display
.
This can be fixed by changing
struct Arg<'arg> {
name: &'arg str,
value: &'arg fmt::Display,
}
to
struct Arg<'a, T: fmt::Display> {
name &'a str,
value: &'a T,
}
but now that is polymorphic (you will need a trait around it to erase T
), so you won't stash it in a vector by value.
You could stash it in the vector boxed, but that would be extra allocations. However, the only thing you ever do with the vector is iterate over it. And you don't need vector for that, you can also use e.g. linked list. And linked list can be completely stored on the stack:
struct Arg<'a, T: fmt::Display> {
name &'a str,
value: &'a T,
prev: Option<&'a Args<'a>>, // ← linked list of args
}
trait Args<'a> {
fn arg<T: fmt::Display>(&'a self, name: &'a str, value: &'a T) -> Arg<'a, T> {
Arg { name: name, value: value, prev: Some(self), }
}
fn next() -> Option<&' Args<'a>>;
fn fmt_value ….
}
impl<'a, T> Args<'a> for Arg<'a, T> {
fn next() -> Option<&' Args<'a>> { prev }
…
}
and now you just create the chain of args on the stack, using the arg
method.
You can put the arg
method for creating the first arg anywhere, but I suggest you put it on the Message itself, extending the struct with pointer to message and the method to actually trigger expansion of the format, so you then call:
Message::new("It's {this} and {that}").arg("this", x).arg("that", y).write_to(file)
But you could also make it stand-alone to make something similar as you have now, i.e.
Message::new("It's {this} and {that}).format_message(file, arg("this", x).arg("that" y))
from message-format.rs.
I haven't been able to get your idea to work yet. The obstacle that I keep hitting is in shortened form here: https://is.gd/p1iBWV
from message-format.rs.
I said that ... and then I got it working:
struct Arg<'a, T: 'a + fmt::Display> {
name: &'a str,
value: &'a T,
prev: Option<&'a Args<'a>>, // ← linked list of args
}
trait Args<'a> {
fn arg<T: fmt::Display>(&'a self, name: &'a str, value: &'a T) -> Arg<'a, T>
where Self: Sized
{
Arg {
name: name,
value: value,
prev: Some(self),
}
}
fn next(&self) -> Option<&'a Args<'a>>;
}
impl<'a, T> Args<'a> for Arg<'a, T>
where T: std::fmt::Display
{
fn next(&self) -> Option<&'a Args<'a>> {
self.prev
}
}
from message-format.rs.
I've pushed some updates ... with my recent changes (so, as of: https://github.com/endoli/message-format.rs/tree/aeea61e7a076892eab89c40d4846be3319c4ebdf), if I apply this diff:
diff --git a/src/lib.rs b/src/lib.rs
index 103e1f3..f939a9c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -85,7 +85,7 @@ pub trait Args<'a> {
fn fmt_value(&self, f: &mut fmt::Formatter) -> fmt::Result;
- fn get(&self, name: &str) -> Option<&fmt::Display>;
+ fn get(&'a self, name: &str) -> Option<&'a Args<'a>>;
fn next(&self) -> Option<&'a Args<'a>>;
}
@@ -97,9 +97,9 @@ impl<'a, T> Args<'a> for Arg<'a, T>
self.value.fmt(f)
}
- fn get(&self, name: &str) -> Option<&fmt::Display> {
+ fn get(&'a self, name: &str) -> Option<&'a Args<'a>> {
if self.name == name {
- Some(self.value)
+ Some(self)
} else if let Some(prev) = self.prev {
prev.get(name)
} else {
I get this set of compilation errors that I haven't sorted out how to solve:
src/ast/simple_format.rs:27:35: 27:38 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements [E0495]
src/ast/simple_format.rs:27 if let Some(value) = args.get(self.variable_name.as_str()) {
^~~
src/ast/simple_format.rs:27:35: 27:38 error: in type `&Args<'_>`, reference has a longer lifetime than the data it references [E0491]
src/ast/simple_format.rs:27 if let Some(value) = args.get(self.variable_name.as_str()) {
^~~
src/ast/simple_format.rs:26:81: 34:6 note: the pointer is valid for the anonymous lifetime #4 defined on the block at 26:80
src/ast/simple_format.rs:26 fn apply_format(&self, stream: &mut fmt::Write, args: &Args) -> fmt::Result {
src/ast/simple_format.rs:27 if let Some(value) = args.get(self.variable_name.as_str()) {
src/ast/simple_format.rs:28 try!(write!(stream, "{}", value));
src/ast/simple_format.rs:29 Ok(())
src/ast/simple_format.rs:30 } else {
src/ast/simple_format.rs:31 // XXX: Should we return an error in this case?
...
src/ast/simple_format.rs:26:81: 34:6 note: but the referenced data is only valid for the anonymous lifetime #3 defined on the block at 26:80
src/ast/simple_format.rs:26 fn apply_format(&self, stream: &mut fmt::Write, args: &Args) -> fmt::Result {
src/ast/simple_format.rs:27 if let Some(value) = args.get(self.variable_name.as_str()) {
src/ast/simple_format.rs:28 try!(write!(stream, "{}", value));
src/ast/simple_format.rs:29 Ok(())
src/ast/simple_format.rs:30 } else {
src/ast/simple_format.rs:31 // XXX: Should we return an error in this case?
...
src/ast/simple_format.rs:26:5: 34:6 help: consider using an explicit lifetime parameter as shown: fn apply_format<'a>(&self, stream: &mut fmt::Write, args: &'a Args)
-> fmt::Result
src/ast/simple_format.rs:26 fn apply_format(&self, stream: &mut fmt::Write, args: &Args) -> fmt::Result {
src/ast/simple_format.rs:27 if let Some(value) = args.get(self.variable_name.as_str()) {
src/ast/simple_format.rs:28 try!(write!(stream, "{}", value));
src/ast/simple_format.rs:29 Ok(())
src/ast/simple_format.rs:30 } else {
src/ast/simple_format.rs:31 // XXX: Should we return an error in this case?
...
src/ast/simple_format.rs:27:30: 27:67 error: cannot infer an appropriate lifetime due to conflicting requirements [E0495]
src/ast/simple_format.rs:27 if let Some(value) = args.get(self.variable_name.as_str()) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/ast/simple_format.rs:28:39: 28:44 note: first, the lifetime cannot outlive the expression at 28:38...
src/ast/simple_format.rs:28 try!(write!(stream, "{}", value));
^~~~~
<std macros>:2:21: 2:52 note: in this expansion of format_args!
src/ast/simple_format.rs:28:18: 28:45 note: in this expansion of write! (defined in <std macros>)
src/ast/simple_format.rs:28:13: 28:47 note: in this expansion of try! (defined in <std macros>)
src/ast/simple_format.rs:28:39: 28:44 note: ...so type `&Args<'_>` of expression is valid during the expression
src/ast/simple_format.rs:28 try!(write!(stream, "{}", value));
^~~~~
<std macros>:2:21: 2:52 note: in this expansion of format_args!
src/ast/simple_format.rs:28:18: 28:45 note: in this expansion of write! (defined in <std macros>)
src/ast/simple_format.rs:28:13: 28:47 note: in this expansion of try! (defined in <std macros>)
src/ast/simple_format.rs:28:39: 28:44 note: but, the lifetime must be valid for the expression at 28:38...
src/ast/simple_format.rs:28 try!(write!(stream, "{}", value));
^~~~~
<std macros>:2:21: 2:52 note: in this expansion of format_args!
src/ast/simple_format.rs:28:18: 28:45 note: in this expansion of write! (defined in <std macros>)
src/ast/simple_format.rs:28:13: 28:47 note: in this expansion of try! (defined in <std macros>)
src/ast/simple_format.rs:28:39: 28:44 note: ...so that reference is valid at the time of borrow
src/ast/simple_format.rs:28 try!(write!(stream, "{}", value));
^~~~~
<std macros>:2:21: 2:52 note: in this expansion of format_args!
src/ast/simple_format.rs:28:18: 28:45 note: in this expansion of write! (defined in <std macros>)
src/ast/simple_format.rs:28:13: 28:47 note: in this expansion of try! (defined in <std macros>)
error: aborting due to 3 previous errors
error: Could not compile `message-format`.
from message-format.rs.
Also ... I'm going to need the value of the argument in some cases ... but once I sort out the above, I have a plan for that.
from message-format.rs.
That compilation issue has been resolved ... moving on with further functionality here.
from message-format.rs.
This is much improved now with a macro:
let message = icu::parse("{name} went to {town}").unwrap();
let town = "Berlin";
assert_eq!(format_message!(ctx, &message, name => "George", town),
"George went to Berlin");
from message-format.rs.
Related Issues (9)
- PluralFormat: Placeholder HOT 1
- Remove HashMaps
- Finish implementing parsing `SelectFormat`. HOT 2
- Finish implementing parsing `PluralFormat`. HOT 2
- Create unified Traits that can be used for any formatting library
- L20n support
- Accessing args for a parsed ICU string HOT 2
- Creating Args from owned values slice
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from message-format.rs.