--- /dev/null
+var composeArgs = require('./composeArgs'),
+ composeArgsRight = require('./composeArgsRight'),
+ createCtorWrapper = require('./createCtorWrapper'),
+ createRecurryWrapper = require('./createRecurryWrapper'),
+ reorder = require('./reorder'),
+ replaceHolders = require('./replaceHolders');
+
+/** Used to compose bitmasks for wrapper metadata. */
+var BIND_FLAG = 1,
+ BIND_KEY_FLAG = 2,
+ CURRY_FLAG = 8,
+ CURRY_RIGHT_FLAG = 16,
+ ARY_FLAG = 128,
+ FLIP_FLAG = 512;
+
+/**
+ * Creates a function that wraps `func` to invoke it with optional `this`
+ * binding of `thisArg`, partial application, and currying.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to wrap.
+ * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper` for more details.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to prepend to those provided to the new function.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
+ * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
+ var isAry = bitmask & ARY_FLAG,
+ isBind = bitmask & BIND_FLAG,
+ isBindKey = bitmask & BIND_KEY_FLAG,
+ isCurry = bitmask & CURRY_FLAG,
+ isCurryRight = bitmask & CURRY_RIGHT_FLAG,
+ isFlip = bitmask & FLIP_FLAG,
+ Ctor = isBindKey ? undefined : createCtorWrapper(func);
+
+ function wrapper() {
+ var length = arguments.length,
+ index = length,
+ args = Array(length);
+
+ while (index--) {
+ args[index] = arguments[index];
+ }
+ if (partials) {
+ args = composeArgs(args, partials, holders);
+ }
+ if (partialsRight) {
+ args = composeArgsRight(args, partialsRight, holdersRight);
+ }
+ if (isCurry || isCurryRight) {
+ var placeholder = wrapper.placeholder,
+ argsHolders = replaceHolders(args, placeholder);
+
+ length -= argsHolders.length;
+ if (length < arity) {
+ return createRecurryWrapper(func, bitmask, createHybridWrapper, placeholder, thisArg, args, argsHolders, argPos, ary, arity - length);
+ }
+ }
+ var thisBinding = isBind ? thisArg : this,
+ fn = isBindKey ? thisBinding[func] : func;
+
+ if (argPos) {
+ args = reorder(args, argPos);
+ } else if (isFlip && args.length > 1) {
+ args.reverse();
+ }
+ if (isAry && ary < args.length) {
+ args.length = ary;
+ }
+ if (this && this !== global && this instanceof wrapper) {
+ fn = Ctor || createCtorWrapper(fn);
+ }
+ return fn.apply(thisBinding, args);
+ }
+ return wrapper;
+}
+
+module.exports = createHybridWrapper;