How to use macro in submodule of another module?

Hello.
I got a module problem.

This is my src/ tree.

src/
├── connection.rs
├── lib.rs
├── main.rs
├── server
│   └── converter.rs
└── server.rs

I want to use track_try_unwrap!() macro in trackable crate in server/converter.rs.
But Rust compiler does not allow me use #[macro_use] in server/converter.
I can only use #[macro_use] in main.rs.

These are my codes of import

main.rs

extern crate bytes;
extern crate slab;
extern crate rml_rtmp;
#[macro_use]
extern crate trackable;

use std::collections::{HashSet};
use std::net::{TcpListener, TcpStream};
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::thread;
use slab::Slab;

use everlong::*;
...

lib.rs

mod connection;
mod server;

pub use connection::{Connection, ConnectionError, ReadResult};
pub use server::{Server, ServerResult};

src/converter.rs

extern crate mpeg2ts;

use mpeg2ts::ts::{TsPacketReader, TsPacketWriter, ReadTsPacket, WriteTsPacket};

pub struct Converter;

impl Converter {
    pub fn convert() {
        let mut writer = TsPacketWriter::new(std::io::stdout());
        let mut reader = TsPacketReader::new(std::io::stdin());

        while let Some(packet) = track_try_unwrap!(reader.read_ts_packet()) {
        //     track_try_unwrap!(writer.write_ts_packet(&packet));
        }
    }
}

Then this is the error.

   Compiling everlong v0.1.0 (/Users/kunosouichirou/Documents/GitHub/Everlong/everlong)
error: cannot find macro `track_try_unwrap` in this scope
  --> src/server/converter.rs:12:34
   |
12 |         while let Some(packet) = track_try_unwrap!(reader.read_ts_packet()) {
   |                                  ^^^^^^^^^^^^^^^^

warning: unused imports: `ReadTsPacket`, `WriteTsPacket`
 --> src/server/converter.rs:3:51
  |
3 | use mpeg2ts::ts::{TsPacketReader, TsPacketWriter, ReadTsPacket, WriteTsPacket};
  |                                                   ^^^^^^^^^^^^  ^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error: aborting due to previous error

error: could not compile `everlong`.

To learn more, run the command again with --verbose.

Help me!

The extern crate syntax is no longer needed, so you should be able to just remove those.

Does importing the macro work?

use trackable::track_try_unwrap;

Do you mean that

#[macro_use]
extern crate trackable;

is not needed?

and yes, I have checked the trackable macro passed rust compiler check.

https://github.com/sile/mpeg2ts/blob/5983273e60784d840be83a2e8db576b3a5f2f66b/examples/parse.rs

I just checked the parse.rs works.


I have tried with these new codes.

main.rs

extern crate bytes;
extern crate slab;
extern crate rml_rtmp;
// #[macro_use]
// extern crate trackable;

use std::collections::{HashSet};
use std::net::{TcpListener, TcpStream};
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::thread;
use slab::Slab;

use everlong::*;

fn main() {
    let address = "0.0.0.0:1935";
    let listener = TcpListener::bind(&address).unwrap();

    let (stream_sender, stream_receiver) = channel();
    thread::spawn(|| {handle_connections(stream_receiver)});

    println!("Listening for connections on {}", address);
    for stream in listener.incoming() {
        println!("New connection!");
        match stream_sender.send(stream.unwrap()) {
            Ok(_) => (),
            Err(error) => panic!("Error sending stream to connection handler: {:?}", error),
        }
    }
}

fn handle_connections(connection_receiver: Receiver<TcpStream>) {
    let mut connections = Slab::new();
    let mut connection_ids = HashSet::new();
    let mut server = Server::new();

    loop {
        match connection_receiver.try_recv() {
            Err(TryRecvError::Disconnected) => panic!("Connection receiver closed"),
            Err(TryRecvError::Empty) => (),
            Ok(stream) => {
                let connection = Connection::new(stream);
                let id = connections.insert(connection);
                let connection = connections.get_mut(id).unwrap();
                connection.connection_id = Some(id);
                connection_ids.insert(id);

                println!("Connection {} started", id);
            }
        }

        let mut ids_to_clear = Vec::new();
        let mut packets_to_write = Vec::new();
        for connection_id in &connection_ids {
            let connection = connections.get_mut(*connection_id).unwrap();
            match connection.read() {
                Err(ConnectionError::SocketClosed) => {
                    println!("Socket closed for id {}", connection_id);
                    ids_to_clear.push(*connection_id);
                },

                Err(error) => {
                    println!("I/O error while reading connection {}: {:?}", connection_id, error);
                    ids_to_clear.push(*connection_id);
                },

                Ok(result) => {
                    match result {
                        ReadResult::NoBytesReceived => (),
                        ReadResult::HandshakingInProgress => (),
                        ReadResult::BytesReceived {buffer, byte_count} => {
                            let mut server_results = match server.bytes_received(*connection_id, &buffer[..byte_count]) {
                                Ok(results) => results,
                                Err(error) => {
                                    println!("Input caused the following server error: {}", error);
                                    ids_to_clear.push(*connection_id);
                                    continue;
                                },
                            };

                            for result in server_results.drain(..) {
                                match result {
                                    ServerResult::OutboundPacket {target_connection_id, packet} => {
                                        packets_to_write.push((target_connection_id, packet));
                                    },

                                    ServerResult::DisconnectConnection {connection_id: id_to_close} => {
                                        ids_to_clear.push(id_to_close);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        for (connection_id, packet) in packets_to_write.drain(..) {
            let connection = connections.get_mut(connection_id).unwrap();
            connection.write(packet.bytes);
        }

        for closed_id in ids_to_clear {
            println!("Connection {} closed", closed_id);
            connection_ids.remove(&closed_id);
            connections.remove(closed_id);
            server.notify_connection_closed(closed_id);
        }
    }
}

converter.rs

extern crate mpeg2ts;

use mpeg2ts::ts::{TsPacketReader, TsPacketWriter, ReadTsPacket, WriteTsPacket};
use trackable::track_try_unwrap;

pub struct Converter;

impl Converter {
    pub fn convert() {
        let mut writer = TsPacketWriter::new(std::io::stdout());
        let mut reader = TsPacketReader::new(std::io::stdin());

        while let Some(packet) = track_try_unwrap!(reader.read_ts_packet()) {
        //     track_try_unwrap!(writer.write_ts_packet(&packet));
        }
    }
}

But it failed...

   Compiling everlong v0.1.0 (/Users/kunosouichirou/Documents/GitHub/Everlong/everlong)
error: cannot find macro `track` in this scope
  --> src/server/converter.rs:13:34
   |
13 |         while let Some(packet) = track_try_unwrap!(reader.read_ts_packet()) {
   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

warning: unused imports: `ReadTsPacket`, `WriteTsPacket`
 --> src/server/converter.rs:3:51
  |
3 | use mpeg2ts::ts::{TsPacketReader, TsPacketWriter, ReadTsPacket, WriteTsPacket};
  |                                                   ^^^^^^^^^^^^  ^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error: aborting due to previous error

error: could not compile `everlong`.

To learn more, run the command again with --verbose.

Do you think there are any other codes to check?

To be honest, I don't have to stick to using trackable in this case.
I can replace track_try_unwrap! with Result::unwrap.

I just want to know how to use macro in submodule...

Well your new error says that it did find the track_try_unwrap! macro. It's just that the macro expanded to something using the track! macro, which was not in scope. You can import that one too

use trackable::{track, track_try_unwrap};
// or
use trackable::*;

And yes, the extern crate thing is never needed anymore. It was necessary before the 2018 edition of Rust was introduced, but it doesn't do anything anymore (besides functioning as a use statement).

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.