Skip to content

Commit

Permalink
packed struct
Browse files Browse the repository at this point in the history
  • Loading branch information
dylan-conway committed Dec 31, 2024
1 parent 73f30ce commit 31b9908
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 118 deletions.
16 changes: 8 additions & 8 deletions src/cli/outdated_command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -366,11 +366,11 @@ pub const OutdatedCommand = struct {
if (resolution.value.npm.version.order(latest.version, string_buf, manifest.string_buf) != .lt) continue;

const package_name_len = package_name.len +
if (dep.behavior.contains(.dev))
if (dep.behavior.dev)
" (dev)".len
else if (dep.behavior.contains(.peer))
else if (dep.behavior.peer)
" (peer)".len
else if (dep.behavior.contains(.optional))
else if (dep.behavior.optional)
" (optional)".len
else
0;
Expand Down Expand Up @@ -489,11 +489,11 @@ pub const OutdatedCommand = struct {

{
// package name
const behavior_str = if (dep.behavior.contains(.dev))
const behavior_str = if (dep.behavior.dev)
" (dev)"
else if (dep.behavior.contains(.peer))
else if (dep.behavior.peer)
" (peer)"
else if (dep.behavior.contains(.optional))
else if (dep.behavior.optional)
" (optional)"
else
"";
Expand Down Expand Up @@ -589,7 +589,7 @@ pub const OutdatedCommand = struct {
.load_from_memory_fallback_to_disk,
) orelse {
const task_id = Install.Task.Id.forManifest(package_name);
if (manager.hasCreatedNetworkTask(task_id, dep.behavior.contains(.optional))) continue;
if (manager.hasCreatedNetworkTask(task_id, dep.behavior.optional)) continue;

manager.startProgressBarIfNone();

Expand All @@ -605,7 +605,7 @@ pub const OutdatedCommand = struct {
manager.allocator,
manager.scopeForPackageName(package_name),
null,
dep.behavior.contains(.optional),
dep.behavior.optional,
);

manager.enqueueNetworkTask(task);
Expand Down
16 changes: 8 additions & 8 deletions src/install/bun.lock.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1518,15 +1518,15 @@ pub fn parseIntoBinaryLockfile(
const dep = lockfile.buffers.dependencies.items[dep_id];

const entry = pkg_map.get(dep.name.slice(lockfile.buffers.string_bytes.items)) orelse {
if (dep.behavior.contains(.optional)) {
if (dep.behavior.optional) {
continue;
}
try dependencyResolutionFailure(&dep, null, allocator, lockfile.buffers.string_bytes.items, source, log, root_pkg_exr.loc);
return error.InvalidPackageInfo;
};

lockfile.buffers.resolutions.items[dep_id] = entry.pkg_id;
lockfile.buffers.dependencies.items[dep_id].behavior.bits.setPresent(.bundled, entry.bundled);
lockfile.buffers.dependencies.items[dep_id].behavior.bundled = entry.bundled;
}

// TODO(dylan-conway) should we handle workspaces separately here for custom hoisting
Expand Down Expand Up @@ -1562,12 +1562,12 @@ pub fn parseIntoBinaryLockfile(

if (pkg_map.get(res_path)) |entry| {
lockfile.buffers.resolutions.items[dep_id] = entry.pkg_id;
dep.behavior.bits.setPresent(.bundled, entry.bundled);
dep.behavior.bundled = entry.bundled;
continue :deps;
}

if (offset == 0) {
if (dep.behavior.contains(.optional)) {
if (dep.behavior.optional) {
continue :deps;
}
try dependencyResolutionFailure(dep, pkg_path, allocator, lockfile.buffers.string_bytes.items, source, log, key.loc);
Expand Down Expand Up @@ -1634,11 +1634,11 @@ pub fn parseIntoBinaryLockfile(
}

fn dependencyResolutionFailure(dep: *const Dependency, pkg_path: ?string, allocator: std.mem.Allocator, buf: string, source: *const logger.Source, log: *logger.Log, loc: logger.Loc) OOM!void {
const behavior_str = if (dep.behavior.contains(.dev))
const behavior_str = if (dep.behavior.dev)
"dev"
else if (dep.behavior.contains(.optional))
else if (dep.behavior.optional)
"optional"
else if (dep.behavior.contains(.peer))
else if (dep.behavior.peer)
"peer"
else if (dep.behavior.isWorkspaceOnly())
"workspace"
Expand Down Expand Up @@ -1718,7 +1718,7 @@ fn parseAppendDependencies(
const dep: Dependency = .{
.name = name.value,
.name_hash = name.hash,
.behavior = if (group_behavior.contains(.peer) and optional_peers_buf.contains(name.hash))
.behavior = if (group_behavior.peer and optional_peers_buf.contains(name.hash))
group_behavior.add(.optional)
else
group_behavior,
Expand Down
120 changes: 40 additions & 80 deletions src/install/dependency.zig
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ pub fn toDependency(
return Dependency{
.name = name,
.name_hash = name_hash,
.behavior = Behavior.fromInt(this[16]),
.behavior = @bitCast(this[16]),
.version = Dependency.Version.toVersion(name, name_hash, this[17..this.len].*, ctx),
};
}
Expand All @@ -162,7 +162,7 @@ pub fn toExternal(this: Dependency) External {
var bytes: External = undefined;
bytes[0..this.name.bytes.len].* = this.name.bytes;
bytes[8..16].* = @as([8]u8, @bitCast(this.name_hash));
bytes[16] = this.behavior.toInt();
bytes[16] = @bitCast(this.behavior);
bytes[17..bytes.len].* = this.version.toExternal();
return bytes;
}
Expand Down Expand Up @@ -1300,112 +1300,72 @@ pub fn fromJS(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JS
return dep.toJS(buf, globalThis);
}

pub const Behavior = struct {
bits: Enum.Set = Enum.Set.initEmpty(),

pub const Enum = enum(u8) {
_unused_1 = 0,
prod = 1,
optional = 2,
dev = 3,
peer = 4,
workspace = 5,
/// Is not set for transitive bundled dependencies
bundled = 6,
_unused_2 = 7,

pub const Set = std.EnumSet(@This());
};

pub fn fromInt(int: u8) Behavior {
return .{ .bits = .{ .bits = .{ .mask = int } } };
}

pub fn toInt(this: Behavior) u8 {
return this.bits.bits.mask;
}

pub fn init(values: std.enums.EnumFieldStruct(Enum, bool, false)) Behavior {
return .{ .bits = Enum.Set.init(values) };
}

pub const prod = Behavior{ .bits = Dependency.Behavior.Enum.Set.initOne(.prod) };
pub const optional = Behavior{ .bits = Dependency.Behavior.Enum.Set.initOne(.optional) };
pub const dev = Behavior{ .bits = Dependency.Behavior.Enum.Set.initOne(.dev) };
pub const peer = Behavior{ .bits = Dependency.Behavior.Enum.Set.initOne(.peer) };
pub const workspace = Behavior{ .bits = Dependency.Behavior.Enum.Set.initOne(.workspace) };
pub const Behavior = packed struct(u8) {
_unused_1: bool = false,
prod: bool = false,
optional: bool = false,
dev: bool = false,
peer: bool = false,
workspace: bool = false,
/// Is not set for transitive bundled dependencies
bundled: bool = false,
_unused_2: bool = false,

pub const prod = Behavior{ .prod = true };
pub const optional = Behavior{ .optional = true };
pub const dev = Behavior{ .dev = true };
pub const peer = Behavior{ .peer = true };
pub const workspace = Behavior{ .workspace = true };

pub inline fn isProd(this: Behavior) bool {
return this.bits.contains(.prod);
return this.prod;
}

pub inline fn isOptional(this: Behavior) bool {
return this.bits.contains(.optional) and !this.bits.contains(.peer);
return this.optional and !this.peer;
}

pub inline fn isOptionalPeer(this: Behavior) bool {
return this.bits.contains(.optional) and this.bits.contains(.peer);
return this.optional and this.peer;
}

pub inline fn isDev(this: Behavior) bool {
return this.bits.contains(.dev);
return this.peer;
}

pub inline fn isPeer(this: Behavior) bool {
return this.bits.contains(.peer);
return this.peer;
}

pub inline fn isWorkspace(this: Behavior) bool {
return this.bits.contains(.workspace);
return this.workspace;
}

pub inline fn isBundled(this: Behavior) bool {
return this.bits.contains(.bundled);
return this.bundled;
}

pub inline fn isWorkspaceOnly(this: Behavior) bool {
return this.bits.contains(.workspace) and
!this.bits.contains(.dev) and
!this.bits.contains(.prod) and
!this.bits.contains(.optional) and
!this.bits.contains(.peer);
return this.workspace and !this.dev and !this.prod and !this.optional and !this.peer;
}

pub inline fn eq(lhs: Behavior, rhs: Behavior) bool {
return lhs.bits.eql(rhs.bits);
return @as(u8, @bitCast(lhs)) == @as(u8, @bitCast(rhs));
}

pub inline fn includes(lhs: Behavior, rhs: Behavior) bool {
return rhs.bits.subsetOf(lhs.bits);
}

pub inline fn contains(this: Behavior, kind: Enum) bool {
return this.bits.contains(kind);
}

pub inline fn add(this: Behavior, kind: Enum) Behavior {
var new = this;
new.bits.insert(kind);
return new;
return @as(u8, @bitCast(lhs)) & @as(u8, @bitCast(rhs)) != 0;
}

pub inline fn insert(this: *Behavior, kind: Enum) void {
this.bits.insert(kind);
}

pub inline fn set(this: Behavior, kind: Enum, value: bool) Behavior {
pub inline fn add(this: Behavior, kind: @Type(.EnumLiteral)) Behavior {
var new = this;
new.bits.setPresent(kind, value);
@field(new, @tagName(kind)) = true;
return new;
}

pub inline fn setMany(this: Behavior, values: std.enums.EnumFieldStruct(Enum, bool, false)) Behavior {
pub inline fn set(this: Behavior, kind: @Type(.EnumLiteral), value: bool) Behavior {
var new = this;
inline for (std.meta.fields(@TypeOf(values))) |field| {
if (@field(values, field.name)) {
new.insert(@field(Enum, field.name));
}
}
@field(new, @tagName(kind)) = value;
return new;
}

Expand Down Expand Up @@ -1463,12 +1423,12 @@ pub const Behavior = struct {
(features.peer_dependencies and this.isPeer()) or
(features.workspaces and this.isWorkspaceOnly());
}
};

comptime {
bun.assert(@as(u8, @bitCast(Behavior.prod.toInt())) == (1 << 1));
bun.assert(@as(u8, @bitCast(Behavior.optional.toInt())) == (1 << 2));
bun.assert(@as(u8, @bitCast(Behavior.dev.toInt())) == (1 << 3));
bun.assert(@as(u8, @bitCast(Behavior.peer.toInt())) == (1 << 4));
bun.assert(@as(u8, @bitCast(Behavior.workspace.toInt())) == (1 << 5));
}
comptime {
bun.assert(@as(u8, @bitCast(Behavior.prod)) == (1 << 1));
bun.assert(@as(u8, @bitCast(Behavior.optional)) == (1 << 2));
bun.assert(@as(u8, @bitCast(Behavior.dev)) == (1 << 3));
bun.assert(@as(u8, @bitCast(Behavior.peer)) == (1 << 4));
bun.assert(@as(u8, @bitCast(Behavior.workspace)) == (1 << 5));
}
};
6 changes: 3 additions & 3 deletions src/install/install.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13342,7 +13342,7 @@ pub const PackageManager = struct {
log_level,
&lazy_package_dir,
package_id,
dep.behavior.contains(.optional),
dep.behavior.optional,
resolution,
)) {
if (is_trusted_through_update_request) {
Expand Down Expand Up @@ -13498,7 +13498,7 @@ pub const PackageManager = struct {
log_level,
&destination_dir,
package_id,
dep.behavior.contains(.optional),
dep.behavior.optional,
resolution,
)) {
if (is_trusted_through_update_request) {
Expand Down Expand Up @@ -15193,7 +15193,7 @@ pub const PackageManager = struct {
else => this.options.remote_package_features,
};
// even if optional dependencies are enabled, it's still allowed to fail
if (failed_dep.behavior.contains(.optional) or !failed_dep.behavior.isEnabled(features)) continue;
if (failed_dep.behavior.optional or !failed_dep.behavior.isEnabled(features)) continue;

if (log_level != .silent) {
if (failed_dep.name.isEmpty() or strings.eqlLong(failed_dep.name.slice(string_buf), failed_dep.version.literal.slice(string_buf), true)) {
Expand Down
31 changes: 16 additions & 15 deletions src/install/lockfile.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4012,17 +4012,18 @@ pub const Package = extern struct {
const dep_version = string_builder.appendWithHash(String, version_string_.slice(string_buf), version_string_.hash);
const sliced = dep_version.sliced(lockfile.buffers.string_bytes.items);

const behavior = group.behavior.setMany(.{
.optional = if (comptime !is_peer) false else i < package_version.non_optional_peer_dependencies_start,
.bundled = package_version_ptr.allDependenciesBundled() or bundled: {
for (package_version.bundled_dependencies.get(manifest.bundled_deps_buf)) |bundled_dep_name_hash| {
if (bundled_dep_name_hash == name.hash) {
break :bundled true;
}
}
break :bundled false;
},
});
var behavior = group.behavior;
if (comptime is_peer) {
behavior.optional = i < package_version.non_optional_peer_dependencies_start;
}
if (package_version_ptr.allDependenciesBundled()) {
behavior.bundled = true;
} else for (package_version.bundled_dependencies.get(manifest.bundled_deps_buf)) |bundled_dep_name_hash| {
if (bundled_dep_name_hash == name.hash) {
behavior.bundled = true;
break;
}
}

const dependency = Dependency{
.name = name.value,
Expand Down Expand Up @@ -5742,11 +5743,11 @@ pub const Package = extern struct {
)) |_dep| {
var dep = _dep;
if (group.behavior.isPeer() and optional_peer_dependencies.contains(external_name.hash)) {
dep.behavior.insert(.optional);
dep.behavior.optional = true;
}

if (bundle_all_deps or bundled_deps.contains(dep.name.slice(lockfile.buffers.string_bytes.items))) {
dep.behavior.insert(.bundled);
dep.behavior.bundled = true;
}

package_dependencies[total_dependencies_count] = dep;
Expand Down Expand Up @@ -7333,9 +7334,9 @@ pub fn jsonStringifyDependency(this: *const Lockfile, w: anytype, dep_id: Depend
try w.beginObject();
defer w.endObject() catch {};

const fields = @typeInfo(Behavior.Enum).Enum.fields;
const fields = @typeInfo(Behavior).Struct.fields;
inline for (fields) |field| {
if (dep.behavior.contains(@enumFromInt(field.value))) {
if (@field(dep.behavior, field.name)) {
try w.objectField(field.name);
try w.write(true);
}
Expand Down
Loading

0 comments on commit 31b9908

Please sign in to comment.