I'm curious if the community has some design approaches to encapsulating
interfaces to multiple generic implementations.  For example, imagine I was
writing an abstract database interface with multiple backing
implementations for different stores (sqlite, pgsql, mysql, etc) and
logging data to different types of loggers (stdout, file, network-attached,
etc).  The goal would be to implement some shared methods (insert, query,
delete) to be delegated to different stores, with logging about the results.

My first approach to this was to create traits, and use them in a struct

trait Logger {
  fn log(&mut self, message: String),
}

trait Store {
  fn insert(&mut self, value: String),
  fn query(&mut self, conditions: String) -> Vec<String>,
  fn delete(&mut self, value: String),
}

struct Database {
  db: Store,
  logger: Logger,
}

AFAICT, this isn't possible - struct fields seem to require concrete types.

Another approach I've considered is using a function with a communication
channel, something like (code probably broken in multiple ways):

enum Event {
  Insert(value: String),
  Query(conditions, response: channel<String>),
  Delete(value: String),
}
fn database(db: Database, logger: Logger, events: chan<Event>) {
  loop {
    match events.recv() {
      // do stuff
    }
  }
}
let (tx, rx) = channel()
spawn {
  database(db, logger, rx);
}
tx.send(Query(my_query));

This seems like it would work, but feels like a hack.  Is there a better
way to do this than using channels?

-Ryan
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to