Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@adrianfilip
Copy link
Contributor

Hi @jdegoes,

This is for #3880.
Let me know if I anything should be changed!

@iravid
Copy link
Member

iravid commented Jun 28, 2020

Hi @adrianfilip, this looks pretty cool and a good addition. I have a few suggestions:

  1. The case classes can be placed outside of the platform-specific trait. Only the constructors need to be there.
  2. It'd be nice if these were not case classes but rather traits or abstract classes, such that we can later implement them using a backing ZStream in ZStream#toInputStream or a future ZSink#toOutputStream.

Copy link
Member

@iravid iravid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @adrianfilip! Done reviewing this thoroughly. This is going to be a great addition.


object ZManagedPlatformSpecificSpec extends ZIOBaseSpec {

val target = new ZManagedPlatformSpecific {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to access it through the ZManaged companion object, I think

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't access it like you mention.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right. We need to modify the ZManaged companion object to extend the ZManagedPlatformSpecific trait.


import zio.blocking.{ Blocking, _ }

private[zio] trait ZInputStream {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this to its own file. It can also be public.

def close(): ZIO[Blocking, Nothing, Unit]
}

private[zio] trait ZOutputStream {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same- separate file and public.

/**
* A functional wrapper over a java.io.InputStream.
*/
private[zio] case class InputStream private (private val is: java.io.InputStream) extends ZInputStream {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can become a constructor for ZInputStream:

object ZInputStream {
  def fromInputStream: ZInputStream = 
    new ZInputStream {
      // implementations
    }
}

/**
* A functional wrapper over a java.io.OutputStream.
*/
private[zio] case class OutputStream private (private val os: java.io.OutputStream) extends ZOutputStream {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as InputStream - this can become a constructor of ZOutputStream.

case 0 => None
case _ => {
val buffer = new java.io.ByteArrayOutputStream();
val data = new Array[Byte](4096);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The chunk size here should be configurable

* A functional wrapper over a java.io.InputStream.
*/
private[zio] case class InputStream private (private val is: java.io.InputStream) extends ZInputStream {
def readN(n: Int): ZIO[Blocking, IOException, Option[Chunk[Byte]]] =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this signature, there's no way for the caller to infer if the input stream is exhausted. How about encoding this as ZIO[Blocking, Option[IOException], Chunk[Byte]], where Some(IOException) is an actual error, None is an end-of-stream signal and a value is a chunk?

I would also suggest to make the non-blocking read optional (using a flag). If the flag is false, don't check available before reading and just let the underlying input stream manage that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion. I think we should remove the available check alltogether if we use the encoding you proposed. And have each implementation decide how it wants to deal with readN on an exhausted stream. I think it makes things simpler.

What do you think?

def skip(n: Long): ZIO[Blocking, IOException, Long] =
effectBlocking(is.skip(n)).refineToOrDie[IOException]

def readAll: ZIO[Blocking, IOException, Option[Chunk[Byte]]] =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be ZIO[Blocking, IOException, Chunk[Byte]] and the blocking can be configured through a flag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand. Looking at ZIO[Blocking, Option[IOException], Chunk[Byte]] from readN I think this place would be a good one to use the same encoding and also drop the available check alltogether (we already get the info from the read return code).

def write(chunk: Chunk[Byte]): ZIO[Blocking, IOException, Unit] =
effectBlocking {
os.write(chunk.toArray)
os.flush()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we always flush?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. No, we don't. I was thinking about treating write + flush as "atomic" in a write, but it doesn't have to be and it would actually reduce performance (because of all that IO). I will remove the flush.

@adrianfilip
Copy link
Contributor Author

adrianfilip commented Jun 28, 2020

@iravid Thanks! Sounds great. I'll make the changes.

@adrianfilip
Copy link
Contributor Author

@iravid I implemented the changes based on your suggestions. I updated my approach as a reply to your comments.
Let me know if this is ok and also if the new ZInputStream and ZOutputStream files should be moved elsewhere.

(The failing tests are unrelated to the PR (i raised a ticket for that #3908).)

@adrianfilip
Copy link
Contributor Author

@jdegoes @iravid I think it's good to go now. Let me know if you think I should change anything.

Copy link
Member

@iravid iravid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks @adrianfilip!

@iravid iravid merged commit e4175c7 into zio:master Jul 15, 2020
@adrianfilip adrianfilip deleted the 3880_ZManaged_integration_improvements branch July 18, 2020 18:21
@iravid iravid mentioned this pull request Jul 31, 2020
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants