Giter VIP home page Giter VIP logo

Comments (7)

jan-hudec avatar jan-hudec commented on September 2, 2024

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.

waywardmonkeys avatar waywardmonkeys commented on September 2, 2024

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.

waywardmonkeys avatar waywardmonkeys commented on September 2, 2024

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.

waywardmonkeys avatar waywardmonkeys commented on September 2, 2024

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.

waywardmonkeys avatar waywardmonkeys commented on September 2, 2024

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.

waywardmonkeys avatar waywardmonkeys commented on September 2, 2024

That compilation issue has been resolved ... moving on with further functionality here.

from message-format.rs.

waywardmonkeys avatar waywardmonkeys commented on September 2, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.