Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

io: Copyn slow- and fast-path asymmetry #1383

Closed
masiulaniec opened this issue Jan 4, 2011 · 4 comments
Closed

io: Copyn slow- and fast-path asymmetry #1383

masiulaniec opened this issue Jan 4, 2011 · 4 comments

Comments

@masiulaniec
Copy link

Copyn has two modes: slower using internal buffering, and faster using ReaderFrom
interface.

In the former case, Copyn(dst, src, N) loops until exactly N bytes are copied, or until
Read or Write error, whichever comes first.

In the latter case, Copyn(dst, src, N) does not loop.

This asymmetry means the caller cannot rely on Copyn to always do this looping, which
initially struck me as its primary function.

I have a diff that modifies Copyn and all ReadersFrom (only bytes.Buffer really) which I
can submit if you agree I've identified the problem correctly.
@peterGo
Copy link
Contributor

peterGo commented Jan 5, 2011

Comment 1:

When the io.Copyn destination implements a ReaderFrom interface, the number of bytes
copied is limited to n by the LimitReader. For example,
package main
import (
    "bytes"
    "fmt"
    "io"
)
func main() {
    pfx := "01234567"
    sfx := "89"
    r := bytes.NewBuffer([]byte(pfx + sfx))
    w := bytes.NewBuffer(nil)
    n, err := io.Copyn(w, r, int64(len(pfx)))
    // 8 <nil>
    fmt.Println(n, err)
    // true true
    fmt.Println(r.String() == sfx, w.String() == pfx)
}

@masiulaniec
Copy link
Author

Comment 2:

In _, err = Copyn(dst, src, N) notice how the meaning of err varies depending on dst:
1) if dst satisfies ReaderFrom, err == nil means N bytes have or have not been copied.
2) if dst does not satisfy ReaderFrom, err == nil means N bytes have been copied.
Consider below program; its output is:
  3 <nil>
  3 <nil>
  3 EOF
  3 <nil>
while I was expecting more consistent:
  3 <nil>
  3 <nil>
  3 EOF
  3 EOF
package main
import (
        "bufio"
        "bytes"
        "io"
        "os"
        "strings"
        "fmt"
)
func main() {
        var w io.Writer
        w = bufio.NewWriter(os.Stdout)
        n, err := io.Copyn(w, strings.NewReader("foo"), 3)
        // 3 <nil>
        fmt.Println(n, err)
        w = bytes.NewBuffer(nil)
        n, err = io.Copyn(w, strings.NewReader("foo"), 3)
        // 3 <nil>
        fmt.Println(n, err)
        w = bufio.NewWriter(os.Stdout)
        n, err = io.Copyn(w, strings.NewReader("foo"), 4)
        // 3 EOF
        fmt.Println(n, err)
        w = bytes.NewBuffer(nil)
        n, err = io.Copyn(w, strings.NewReader("foo"), 4)
        // 3 <nil>
        fmt.Println(n, err)
}

@rsc
Copy link
Contributor

rsc commented Jan 5, 2011

Comment 3:

3821044

Owner changed to r...@golang.org.

Status changed to Started.

@rsc
Copy link
Contributor

rsc commented Jan 5, 2011

Comment 4:

This issue was closed by revision 0f26608.

Status changed to Fixed.

@golang golang locked and limited conversation to collaborators Jun 24, 2016
@rsc rsc removed their assignment Jun 22, 2022
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants