0

Note: I am using iced for the GUI TextInput and tokio for the networking TcpStream

I have the following:

#[derive(Debug, Clone)]
enum Message {
    Session(Result<Connection, ConnectionError>), //Async Handler
    SendMessage,
    Send(Result<Connection, ConnectionError>), //Async Handler
    InputChanged(String),
    Button(usize, ButtonMessage),
    None,
}

#[derive(Debug)]
enum ConnectionError {
    ConnectError(usize),
    SendError(usize),
}

#[derive(Debug)]
struct Connection {
    stream: TcpStream,
    loc: usize,
}

Problem is that my Connection struct contains a TcpStream that cannot be cloned (it wouldn't logistically make sense for it to be cloned anyway).

So I get the error...

>the trait bound `Connection: Clone` is not satisfied
  --> src\main.rs:27:10
   |
27 |     Session(Result<Connection, ConnectionError>), //Async Handler
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
   |
   = note: required because of the requirements on the impl of `Clone` for `std::result::Result<Connection, ConnectionError>`
   = note: required by `clone`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

>error[E0277]: the trait bound `ConnectionError: Clone` is not satisfied
  --> src\main.rs:27:10
   |
27 |     Session(Result<Connection, ConnectionError>), //Async Handler
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
   |
   = note: required because of the requirements on the impl of `Clone` for `std::result::Result<Connection, ConnectionError>`
   = note: required by `clone`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

>error[E0277]: the trait bound `Connection: Clone` is not satisfied
  --> src\main.rs:29:7
   |
29 |     Send(Result<Connection, ConnectionError>), //Async Handler
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
   |
   = note: required because of the requirements on the impl of `Clone` for `std::result::Result<Connection, ConnectionError>`
   = note: required by `clone`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

>error[E0277]: the trait bound `ConnectionError: Clone` is not satisfied
  --> src\main.rs:29:7
   |
29 |     Send(Result<Connection, ConnectionError>), //Async Handler
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
   |
   = note: required because of the requirements on the impl of `Clone` for `std::result::Result<Connection, ConnectionError>`
   = note: required by `clone`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

So I removed the Clone

#[derive(Debug)]
enum Message {
    Session(Result<Connection, ConnectionError>), //Async Handler
    SendMessage,
    Send(Result<Connection, ConnectionError>), //Async Handler
    InputChanged(String),
    Button(usize, ButtonMessage),
    None,
}

and get the following errors:

>the trait bound `Message: Clone` is not satisfied
   --> src\main.rs:516:15
    |
516 |         let input = TextInput::new(
    |                     ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Message`
    |
   ::: C:\Users\bratl\.cargo\registry\src\github.com-1ecc6299db9ec823\iced_native-0.3.0\src\widget\text_input.rs:84:22
    |
84  |         F: 'static + Fn(String) -> Message,
    |                      --------------------- required by this bound in `iced_native::widget::text_input::TextInput::<'a, Message, Renderer>::new`

>error[E0599]: no method named `padding` found for struct `iced_native::widget::text_input::TextInput<'_, Message, iced_graphics::renderer::Renderer<iced_wgpu::backend::Backend>>` in the current scope
   --> src\main.rs:522:4
    |
26  | enum Message {
    | ------------ doesn't satisfy `Message: Clone`
...
522 |         .padding(15)
    |          ^^^^^^^ private field, not a method
    |
    = note: the method `padding` exists but the following trait bounds were not satisfied:
            `Message: Clone`

So I went to where the TextInput was located and removed the Clone as well.

#[derive(Debug)]
struct ClientAdminChatPaneContent {
    scroll: scrollable::State,
    input: text_input::State,
    input_value: String,
}


#[derive(Debug)]
enum ChatPaneMessage {
    InputChanged(String),
}

impl ClientAdminChatPaneContent {
    fn new() -> Self {
        ClientAdminChatPaneContent { 
            scroll: scrollable::State::new(),
            input: text_input::State::new(),
            input_value: String::from(""),
        }
    }

    fn update(&mut self, message: ChatPaneMessage) {
        match message {
            ChatPaneMessage::InputChanged(value) => {
                //println!("Input Changed: {}", value);
                self.input_value = value;
            }
        }
    }

    fn view(&mut self) -> Element<Message> {

        //Text Input
        let input = TextInput::new(
            &mut self.input,
            "Message to Client",
            &self.input_value,
            Message::InputChanged,
        )
        .padding(15)    
        .size(30)
        .on_submit(Message::SendMessage);
        
        let text_input_container:Container<Message> = Container::new(input)
            .width(Length::Fill)
            .height(Length::Units(80))
            .padding(10);

        let scroll = Scrollable::new(&mut self.scroll)
            .width(Length::Fill)
            .spacing(10)
            .align_items(Align::Start);

        let scroll_container:Container<Message> = Container::new(scroll)
            .width(Length::Fill)
            .height(Length::Fill)
            .padding(10);

        let mut content = Column::new()
            .spacing(5);

        content = content.push(scroll_container);
        content = content.push(text_input_container);

        Container::new(content)
            .width(Length::Fill)
            .height(Length::Fill)
            .padding(5)
            .center_y()
            .into()
    }

    fn clear_text(&mut self) {
        self.input_value = String::from("");
    }
}

And I get a new error:

>the trait bound `Message: Clone` is not satisfied
   --> src\main.rs:516:15
    |
516 |         let input = TextInput::new(
    |                     ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Message`
    |
   ::: C:\Users\bratl\.cargo\registry\src\github.com-1ecc6299db9ec823\iced_native-0.3.0\src\widget\text_input.rs:84:22
    |
84  |         F: 'static + Fn(String) -> Message,
    |                      --------------------- required by this bound in `iced_native::widget::text_input::TextInput::<'a, Message, Renderer>::new`

As to why, I'm not sure why let input = TextInput::new( needs to implement Clone. But, assuming I need this struct to implement Clone, WITHOUT Message implementing Clone due to the TCP...

How do I get clone for a specific item, such as a TextInput without deriving it for every single item Or Is this an entirely different issue?

Michael Anderson
  • 70,661
  • 7
  • 134
  • 187
impression7vx
  • 1,728
  • 1
  • 20
  • 50
  • These three facts can't all be true: (1) `Message` contains `Connection`. (2) `Message` derives `Clone`. (3) `Connection` does not implement `Clone`. At this point, there's no way anyone else can help you: *you* must decide which of those three facts has to give so the others can stay. Personally, I suspect you should eliminate (1) -- in what sense is it meaningful for a *message* to contain a *connection*? -- but it's ultimately determined by how you're using it. There's no general hack or workaround; a thing either is `Clone` or it isn't. I don't know what more you expect to hear. – trent Mar 24 '21 at 21:02
  • It might help to introduce some indirection in the data stored in your structs, so that they can be cloneable. You could wrap TcpStream in Rc (and RefCell if you need to mutate it). An Rc can be cloned without cloning the reference it owns, since it just increments the internal refcount – transistor Mar 24 '21 at 21:59
  • @trentcl I apologize. I 100% see what you are saying. And I totally agree that a `Message` should not contain a `Connection`. I was trying to return a `Connection` from an asynchronous function, say after a `send` function for the `TcpStream`. I realize now that was a mistake. Thanks! – impression7vx Mar 25 '21 at 14:36
  • There's no need to apologize! Glad I could help, even if only in a small way. – trent Mar 25 '21 at 14:43
  • Not that I quite understand how to fix it, or the idea that I can return a `Result<(), ConnectionError>` kind of blows me a way. Little by little. :) – impression7vx Mar 25 '21 at 15:37

0 Answers0