Skip to content

Instantly share code, notes, and snippets.

@izderadicka
Last active October 7, 2019 18:00
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save izderadicka/f84d828b8fde48fb7e37d24324e5f38d to your computer and use it in GitHub Desktop.
Polymorphism Rust
use std::io::{self, Write, Seek};
pub struct Writer<W> {
inner: W
}
impl <W:Write> Writer<WrapperUnseekable<W>> {
pub fn new_unseekable(inner: W) -> Self {
Writer{
inner: WrapperUnseekable::new(inner)
}
}
}
impl <W:Write+Seek> Writer<WrapperSeekable<W>> {
pub fn new(inner: W) -> Self {
Writer{
inner: WrapperSeekable::new(inner)
}
}
}
impl <W:MaySeek> Writer<W> {
pub fn check_can_seek(&self) -> bool {
self.inner.can_seek()
}
pub fn write(&mut self, buf: &[u8]) -> io::Result<()> {
self.inner.write_all(buf)
}
pub fn position(&mut self) -> io::Result<u64> {
self.inner.position()
}
}
impl <T, W:RetunsInner<T>> RetunsInner<T> for Writer<W> {
fn unwrap(self) -> T {
self.inner.unwrap()
}
}
pub trait MaySeek: Write {
fn can_seek(&self) -> bool;
fn position(&mut self) -> io::Result<u64>;
}
pub trait RetunsInner<T> {
fn unwrap(self) ->T;
}
pub struct WrapperSeekable<W>(W);
pub struct WrapperUnseekable<W>(W, u64);
impl <W:Write+Seek> WrapperSeekable <W> {
fn new(inner:W) -> Self {
WrapperSeekable(inner)
}
}
impl <W> RetunsInner<W>for WrapperSeekable<W> {
fn unwrap(self) -> W {
self.0
}
}
impl <W:Write> Write for WrapperSeekable<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
impl <W:Write+Seek> MaySeek for WrapperSeekable <W> {
fn can_seek(&self) -> bool {
true
}
fn position(&mut self) -> io::Result<u64> {
self.0.seek(io::SeekFrom::Current(0))
}
}
impl <W:Write> WrapperUnseekable <W> {
fn new(inner:W) -> Self {
WrapperUnseekable(inner, 0)
}
}
impl <W> RetunsInner<W>for WrapperUnseekable<W> {
fn unwrap(self) -> W {
self.0
}
}
impl <W:Write> MaySeek for WrapperUnseekable <W> {
fn can_seek(&self) -> bool {
false
}
fn position(&mut self) -> io::Result<u64> {
Ok(self.1)
}
}
impl <W:Write> Write for WrapperUnseekable<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let res = self.0.write(buf);
if let Ok(n) = res {self.1 += n as u64}
res
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
use std::io::{self, Write, Seek};
pub struct Writer<'a> {
inner: Box<dyn MaySeek+'a>
}
impl <'a> Writer<'a> {
pub fn new_unseekable<W:Write+'a>(inner: W) -> Self {
Writer{
inner: Box::new(WrapperUnseekable::new(inner))
}
}
pub fn new<W:Write+Seek+'a>(inner: W) -> Self {
Writer{
inner: Box::new(WrapperSeekable::new(inner))
}
}
}
impl <'a> Writer<'a> {
pub fn check_can_seek(&self) -> bool {
self.inner.can_seek()
}
pub fn write(&mut self, buf: &[u8]) -> io::Result<()> {
self.inner.write_all(buf)
}
pub fn position(&mut self) -> io::Result<u64> {
self.inner.position()
}
}
trait MaySeek: Write {
fn can_seek(&self) -> bool;
fn position(&mut self) -> io::Result<u64>;
}
struct WrapperSeekable<W>(W);
struct WrapperUnseekable<W>(W, u64);
impl <W:Write+Seek> WrapperSeekable <W> {
fn new(inner:W) -> Self {
WrapperSeekable(inner)
}
}
impl <W:Write> Write for WrapperSeekable<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
impl <W:Write+Seek> MaySeek for WrapperSeekable <W> {
fn can_seek(&self) -> bool {
true
}
fn position(&mut self) -> io::Result<u64> {
self.0.seek(io::SeekFrom::Current(0))
}
}
impl <W:Write> WrapperUnseekable <W> {
fn new(inner:W) -> Self {
WrapperUnseekable(inner, 0)
}
}
impl <W:Write> MaySeek for WrapperUnseekable <W> {
fn can_seek(&self) -> bool {
false
}
fn position(&mut self) -> io::Result<u64> {
Ok(self.1)
}
}
impl <W:Write> Write for WrapperUnseekable<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let res = self.0.write(buf);
if let Ok(n) = res {self.1 += n as u64}
res
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
use std::io::{self, Write, Seek};
pub struct Writer<'a, T> {
inner: Box<dyn MaySeek<T>+'a>
}
impl <'a,W> Writer<'a,W>
where W: Write+'a
{
pub fn new_unseekable(inner: W) -> Self
{
Writer{
inner: Box::new(WrapperUnseekable::new(inner)),
}
}
pub fn new(inner: W) -> Self
where W:Seek
{
Writer{
inner: Box::new(WrapperSeekable::new(inner)),
}
}
}
impl <'a,T:Write> Writer<'a,T> {
pub fn check_can_seek(&self) -> bool {
self.inner.can_seek()
}
pub fn write(&mut self, buf: &[u8]) -> io::Result<()> {
self.inner.write_all(buf)
}
pub fn position(&mut self) -> io::Result<u64> {
self.inner.position()
}
pub fn unwrap(&mut self) -> T {
self.inner.into_inner()
}
}
trait MaySeek<W:Write>: Write {
fn can_seek(&self) -> bool;
fn position(&mut self) -> io::Result<u64>;
fn into_inner(&mut self) -> W;
}
macro_rules! inner {
($self:ident) => {
match $self.0 {
Some(ref mut i) => i,
None => return Err(io::Error::new(io::ErrorKind::Other, "Wrapper is already consumed"))
}
};
}
struct WrapperSeekable<W>(Option<W>);
struct WrapperUnseekable<W>(Option<W>, u64);
impl <W:Write+Seek> WrapperSeekable <W> {
fn new(inner:W) -> Self {
WrapperSeekable(Some(inner))
}
}
impl <W:Write> Write for WrapperSeekable<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
inner!(self).write(buf)
}
fn flush(&mut self) -> io::Result<()> {
inner!(self).flush()
}
}
impl <W:Write+Seek> MaySeek<W> for WrapperSeekable <W> {
fn can_seek(&self) -> bool {
true
}
fn position(&mut self) -> io::Result<u64> {
inner!(self).seek(io::SeekFrom::Current(0))
}
fn into_inner(&mut self) -> W {
self.0.take().unwrap()
}
}
impl <W:Write> WrapperUnseekable <W> {
fn new(inner:W) -> Self {
WrapperUnseekable(Some(inner), 0)
}
}
impl <W:Write> MaySeek<W> for WrapperUnseekable <W> {
fn can_seek(&self) -> bool {
false
}
fn position(&mut self) -> io::Result<u64> {
Ok(self.1)
}
fn into_inner(&mut self) -> W {
self.0.take().unwrap()
}
}
impl <W:Write> Write for WrapperUnseekable<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let res = inner!(self).write(buf);
if let Ok(n) = res {self.1 += n as u64}
res
}
fn flush(&mut self) -> io::Result<()> {
inner!(self).flush()
}
}
use std::io::{self, Write, Seek, SeekFrom};
type SeekFn<W> = for<'a> fn(&'a mut W, SeekFrom)->io::Result<u64>;
enum WriterFlavour<W> {
CanSeek{
seek: SeekFn<W>
},
CannotSeek {
pos: u64
}
}
pub struct Writer<W> {
inner: W,
flavour: WriterFlavour<W>
}
impl <W:Write> Writer<W> {
pub fn new_unseekable(inner: W) -> Self {
Writer{
inner,
flavour: WriterFlavour::CannotSeek{ pos: 0}
}
}
pub fn new(inner: W) -> Self
where W:Seek
{
Writer{
inner,
flavour: WriterFlavour::CanSeek{ seek: Seek::seek}
}
}
pub fn check_can_seek(&self) -> bool {
match self.flavour {
WriterFlavour::CannotSeek{..} => false,
WriterFlavour::CanSeek{..} => true
}
}
pub fn write(&mut self, buf: &[u8]) -> io::Result<()> {
let res = self.inner.write_all(buf);
if let (Ok(()), WriterFlavour::CannotSeek{ref mut pos}) = (&res, &mut self.flavour) {
*pos += buf.len() as u64
};
res
}
pub fn position(&mut self) -> io::Result<u64> {
match self.flavour {
WriterFlavour::CannotSeek{pos} => Ok(pos),
WriterFlavour::CanSeek{seek} => seek(&mut self.inner, SeekFrom::Current(0))
}
}
pub fn unwrap(self) -> W {
self.inner
}
}
use std::io::Cursor;
use seek_test::*;
fn main() {
let w1: Vec<u8> = Vec::new();
let w2 = Cursor::new(Vec::<u8>::new());
let mut writer1 = Writer::new_unseekable(w1);
let mut writer2 = Writer::new(w2);
assert!(!writer1.check_can_seek());
assert!(writer2.check_can_seek());
writer1.write(b"abc").unwrap();
writer2.write(b"cde").unwrap();
assert_eq!(3, writer1.position().unwrap());
assert_eq!(3, writer2.position().unwrap());
// this cannot be achieved with trait object,
// because there is no way to own back type
// turned to trait object ?
let returned_w1 = writer1.unwrap();
let returned_w2 = writer2.unwrap().into_inner();
assert_eq!(b"abc", &returned_w1[..]);
assert_eq!(b"cde", &returned_w2[..]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment