Repository: vapor/vapor
File: Sources/Vapor/Response/Response.swift (Swift)

Code before:

        func decode<C>(_ content: C.Type, using decoder: ContentDecoder) throws -> C where C : Content {
            guard let body = self.response.body.buffer else {
                throw Abort(.unprocessableEntity)
            }
            var decoded = try decoder.decode(C.self, from: body, headers: self.response.headers)
            try decoded.afterDecode()
            return decoded
        }
    }

    public var content: ContentContainer {
        get {
            return _ContentContainer(response: self)
        }
        set {
            // ignore since Request is a reference type
        }
    }
    
    private let _version: NIOLockedValueBox<HTTPVersion>
    private let _status: NIOLockedValueBox<HTTPResponseStatus>
    private let _headers: NIOLockedValueBox<HTTPHeaders>
    private let _body: NIOLockedValueBox<Body>
    private let _upgrader: NIOLockedValueBox<Upgrader?>
    private let _storage: NIOLockedValueBox<Storage>
    
    // MARK: Init
    
    /// Creates a new `Response`.
    ///
    ///     let res = Response(status: .ok)
    ///
    /// - parameters:
    ///     - status: `HTTPResponseStatus` to use. This defaults to `HTTPResponseStatus.ok`
    ///     - version: `HTTPVersion` of this response, should usually be (and defaults to) 1.1.
    ///     - headers: `HTTPHeaders` to include with this response.
    ///                Defaults to empty headers.
    ///                The `"Content-Length"` and `"Transfer-Encoding"` headers will be set automatically.
    ///     - body: `Body` for this response, defaults to an empty body.
    ///             See `Response.Body` for more information.
    public convenience init(
        status: HTTPResponseStatus = .ok,
        version: HTTPVersion = .init(major: 1, minor: 1),
        headers: HTTPHeaders = .init(),
        body: Body = .empty
    ) {
        self.init(
            status: status,
            version: version,
            headersNoUpdate: headers,

Review comment (suggestion):
Fine-grained locking is all well and good for efficiency, but this is an awful lot of additional allocations on a per-response basis. You can easily combine, at the very least, `version`, `status`, and `headers` under a single lock - it's exceedingly rare (in fact, it might never happen at all) to need to access any of these values simultaneously with one or both of the others from another thread, so contention ought not to be an issue. It might even be reasonable to include `body` in the same lock as well, though I'm less certain on that one.

(Truthfully, I might wonder if it didn't make more sense to put _everything_ under a single lock, maybe with the exception of `storage`.)

Code after:

        func encode<C>(_ content: C, using encoder: ContentEncoder) throws where C : Content {
            var content = content
            try content.beforeEncode()
            try self.response.responseBox.withLockedValue { box in
                var body = box.body.byteBufferAllocator.buffer(capacity: 0)
                try encoder.encode(content, to: &body, headers: &box.headers)
                box.body = .init(buffer: body, byteBufferAllocator: box.body.byteBufferAllocator)
            }
        }

        func decode<C>(_ content: C.Type, using decoder: ContentDecoder) throws -> C where C : Content {
            var decoded = try self.response.responseBox.withLockedValue { box in
                guard let body = box.body.buffer else {
                    throw Abort(.unprocessableEntity)
                }
                return try decoder.decode(C.self, from: body, headers: box.headers)
            }
            try decoded.afterDecode()
            return decoded
        }
    }

    public var content: ContentContainer {
        get {
            return _ContentContainer(response: self)
        }
        set {
            // ignore since Request is a reference type
        }
    }
    
    struct ResponseBox: Sendable {
        var version: HTTPVersion
        var status: HTTPResponseStatus
        var headers: HTTPHeaders
        var body: Body {
            didSet {
                self.headers.updateContentLength(body.count)
            }
        }
        var upgrader: Upgrader?
        // If `true`, don't serialize the body.
        var forHeadRequest: Bool

    }
    
    let responseBox: NIOLockedValueBox<ResponseBox>
    private let _storage: NIOLockedValueBox<Storage>
    
    // MARK: Init