1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package gatefs provides an implementation of the FileSystem
6// interface that wraps another FileSystem and limits its concurrency.
7package gatefs // import "golang.org/x/tools/godoc/vfs/gatefs"
8
9import (
10	"fmt"
11	"os"
12
13	"golang.org/x/tools/godoc/vfs"
14)
15
16// New returns a new FileSystem that delegates to fs.
17// If gateCh is non-nil and buffered, it's used as a gate
18// to limit concurrency on calls to fs.
19func New(fs vfs.FileSystem, gateCh chan bool) vfs.FileSystem {
20	if cap(gateCh) == 0 {
21		return fs
22	}
23	return gatefs{fs, gate(gateCh)}
24}
25
26type gate chan bool
27
28func (g gate) enter() { g <- true }
29func (g gate) leave() { <-g }
30
31type gatefs struct {
32	fs vfs.FileSystem
33	gate
34}
35
36func (fs gatefs) String() string {
37	return fmt.Sprintf("gated(%s, %d)", fs.fs.String(), cap(fs.gate))
38}
39
40func (fs gatefs) RootType(path string) vfs.RootType {
41	return fs.fs.RootType(path)
42}
43
44func (fs gatefs) Open(p string) (vfs.ReadSeekCloser, error) {
45	fs.enter()
46	defer fs.leave()
47	rsc, err := fs.fs.Open(p)
48	if err != nil {
49		return nil, err
50	}
51	return gatef{rsc, fs.gate}, nil
52}
53
54func (fs gatefs) Lstat(p string) (os.FileInfo, error) {
55	fs.enter()
56	defer fs.leave()
57	return fs.fs.Lstat(p)
58}
59
60func (fs gatefs) Stat(p string) (os.FileInfo, error) {
61	fs.enter()
62	defer fs.leave()
63	return fs.fs.Stat(p)
64}
65
66func (fs gatefs) ReadDir(p string) ([]os.FileInfo, error) {
67	fs.enter()
68	defer fs.leave()
69	return fs.fs.ReadDir(p)
70}
71
72type gatef struct {
73	rsc vfs.ReadSeekCloser
74	gate
75}
76
77func (f gatef) Read(p []byte) (n int, err error) {
78	f.enter()
79	defer f.leave()
80	return f.rsc.Read(p)
81}
82
83func (f gatef) Seek(offset int64, whence int) (ret int64, err error) {
84	f.enter()
85	defer f.leave()
86	return f.rsc.Seek(offset, whence)
87}
88
89func (f gatef) Close() error {
90	f.enter()
91	defer f.leave()
92	return f.rsc.Close()
93}
94